The Details

The Tutorial allows you to perfectly use Objenesis. However, if you want implementation details, tools and more power, you're at the right place.

# Test your environment

Depending on your JVM and security manager, Objenesis might not be able to instantiate some of your classes. If that's the case, first, we are highly interested in knowing this limitation.

Then, to prevent this, we provide a TCK to run in your environment. You can find it on our download page. It will print a report to the standard output. Exceptions, if they occur, will be printed out to the standard error. Tests are run against ObjenesisStd and ObjenesisSerializer and are made of every kind of class types you might want to instantiate. So you can check if all of them or at least the kind you want are correctly instantiated.

To launch from the command line, just type

    java -jar objenesis-${project.version}-tck.jar

Note that the Objenesis jar is bundled in the TCK so no special classpath is needed.

To launch from within an application server, the easiest is to bundle it in your application and to call `org.objenesis.tck.Main.main()` from your code.

## Java Platform Module System and Integrity by default

Objenesis is doing some sneaky things and later versions of Java requires you to approve them to use them.

- If you get

      Exception in thread "main" java.lang.NoClassDefFoundError: sun/misc/Unsafe

  Add

      --add-modules jdk.unsupported

- If you get

      Exception in thread "main" java.lang.reflect.InaccessibleObjectException:
      Unable to make zzz.xxx accessible: module yyy does not "opens zzz" to module org.objenesis

  Add

      --add-opens yyy/zzz=org.objenesis

## Android

Objenesis also works on Dalvik, the Android VM. So a TCK is also provided for it in the form of an apk. You can also find it on download page. Just use the following command to install and run it.

    adb install -r objenesis-tck-android-${project.version}.apk
    adb shell am instrument -w org.objenesis.tck.android/.TckInstrumentation

# Exception Handling

If something wrong occurs using Objenesis, you will normally get an ObjenesisException wrapping the real exception. It is a RuntimeException so you don't have to catch it. Some reasons why it fails:

- Using ObjenesisSerializer with a class that isn't `Serializable`.
- Using ObjenesisSerializer, the constructor of the first parent class that isn't `Serializable` throws an exception.
- Your SecurityManager prevents Objenesis from working normally.
- Objenesis isn't able to work for some reason. Please tell us

# ObjectInstantiator caching

ObjenesisBase provides a built-in cache that is activated by default. This cache keeps ObjectInstantiator instances per Class. This improves performance quite a lot when the same Class is frequently instantiated. For this reason, it is recommended to reuse Objenesis instances whenever possibly or to keep is as a singleton in your favorite dependency injection framework.

However, you can always disable the cache if needed.

        Objenesis o = new ObjenesisStd(false); // cache disabled

The cache should behave correctly in an application server and not cause any memory leaks.

# Use you own strategy

As you've seen in the Tutorial, Objenesis implementations are determining the best instantiator using a strategy. It might occurs that you need to implement your own strategy. Two possible reasons I can think of are that

- You want to specialize for a given JVM. Default strategies are supporting all JVMs. This has a little performance cost so you might want to provide a strategy that is optimized for your JVM.

      public class Sun14Strategy implements InstantiatorStrategy {
          public ObjectInstantiator newInstantiatorOf(Class type) {
              // return sun dedicated instantiator
              return new SunReflectionFactoryInstantiator(type);
          }
      }

- Objenesis doesn't support your environment by default. In that case, we would be really happy to add this support in our next version and meanwhile, you can use your own strategy and instantiator to fix this.

From there, you can use this new strategy.

    // Directly
    Objenesis o = new ObjenesisBase(new Sun14Strategy());

    // Or inside your Objenesis own implementation
    public class ObjenesisSun14 extends ObjenesisBase {
        public ObjenesisSun14() {
           super(new Sun14Strategy());
        }
    }

Also, if Objenesis can't find the right instantiator to use by itself, this doesn't mean it doesn't bundle an instantiator that works on your platform. To try to find one, we provide a nice tool that will run through all the instantiators and tell you which ones work

    java -cp objenesis-${project.version}-tck.jar org.objenesis.tck.search.SearchWorkingInstantiator

Some culprits:

- Some instantiators are made to mimic the Java serialization. It means they will call the default constructor of the first non-serializable class
- Some instantiators only works if the class is serializable
- Some instantiators will in fact call the default constructor
- Depending on your security manager, classes coming from a low level class loader might not be instantiable

# The Evil ObjenesisHelper

Static methods are considered a really bad practice. They can't be mocked or replace easily. Worst, if the class keep a static state, you will fell in class loading issues, memory leaks, module dependencies and so on. We strongly recommend you not to use them.

However, if for some reason that we prefer ignore, you still want to use Objenesis in a static way, you can do so. It's called ObjenesisHelper.

We prefer to provide it knowing that some of you will code it anyway. It a wrapper over an ObjenesisStd and ObjenesisSerializer instance which are kept statically.

It can't be more straightforward to use:

       Object o1 = ObjenesisHelper.newInstance(MyClass.class);
       Object o2 = ObjenesisHelper.newSerializableInstance(MyClass.class);
       ObjectInstantiator o3 = ObjenesisHelper.getInstantiatorOf(MyClass.class);
       ObjectInstantiator o4 = ObjenesisHelper.getSerializableObjectInstantiatorOf(MyClass.class);

# Serializing instantiator details

The instantiator returned by `SerializingInstantiatorStrategy` will do the following.

- Fail is the class is not serializable
- Call the no-arg constructor of the first none serializable class. Just like the serialization would do
- `Externalizable` classes won't have a special treatment. If you want one, implement it yourself
- No serializable specific method is called (e.g. `readResolve, readExternal, readObject, readObjectNoData`)