Core Java

Objenesis Hello World Example

In Java, object instantiation typically involves invoking a constructor using the new keyword or reflective instantiation via Constructor.newInstance(). However, these approaches require that a class has an accessible constructor, which isn’t always ideal or even possible in some advanced scenarios like proxy creation, mocking, serialization frameworks, or code generation libraries. This is where Objenesis comes into play. Let’s see what this is all about in our Objenesis Hello World example.

Objenesis is a Java library that allows you to instantiate objects without calling their constructors. It bypasses constructor invocation and directly allocates memory for an object instance.

This article introduces Objenesis, explains how to set it up, and demonstrates how to use its instantiation strategies: ObjenesisStd, ObjenesisSerializer, and ObjenesisHelper.

1. What is Objenesis?

Objenesis is a Java library designed for advanced object instantiation. It allows developers to create objects of arbitrary classes without invoking their constructors. This is helpful in several advanced use cases, such as:

  • Creating instances of classes without no-arg constructors
  • Bypassing constructors for performance optimization
  • Creating mock objects in unit testing frameworks
  • De-serializing objects without executing initialization logic

Objenesis internally uses sun.misc.Unsafe, reflection, or bytecode manipulation depending on the JVM and platform to allocate object memory.

2. Adding Objenesis to Your Project

Before you can use Objenesis, you need to add it to your project. If you are using Maven, include the following dependency in your pom.xml.

    <dependencies>
        <dependency>
            <groupId>org.objenesis</groupId>
            <artifactId>objenesis</artifactId>
            <version>3.4</version>
        </dependency>
    </dependencies>

This dependency brings the core Objenesis library into your project. If you are using Gradle, add this to your build.gradle:

implementation 'org.objenesis:objenesis:3.4'

3. Basic Usage of Objenesis

Let’s begin by demonstrating how to instantiate a class without invoking its constructor.

public class ObjenesisExample {

    public static class MyClass {

        private MyClass() {
            throw new RuntimeException("Constructor should not be called!");
        }

        public void sayHello() {
            System.out.println("Hello from MyClass!");
        }
    }

    public static void main(String[] args) {
        Objenesis objenesis = new ObjenesisStd();
        MyClass instance = objenesis.newInstance(MyClass.class);
        instance.sayHello();
    }
}

In this example, the MyClass constructor is private and throws an exception if called. Using ObjenesisStd, we are able to instantiate MyClass without triggering the constructor logic, thus avoiding the exception. This showcases the core functionality of Objenesis, which is constructor-free instantiation.

4. Compared with Traditional Instantiation

In Java, creating an object using the new keyword or reflection will always trigger the constructor. This is usually desired behavior, but it becomes a limitation in cases where constructors throw exceptions, execute expensive logic, or are intentionally private. Objenesis offers a way around this by allowing object instantiation without invoking any constructor.

Let’s first look at what happens when using the new keyword.

Using the new Keyword

public class ObjenesisExample2 {

    public static class MyClass {

        private MyClass() {
            throw new RuntimeException("Constructor called!");
        }

        public void greet() {
            System.out.println("Greetings from MyClass!");
        }
    }

    public static void main(String[] args) {
        // Will throw RuntimeException
        MyClass instance = new MyClass();
        instance.greet();
    }
}

Here, the new keyword invokes the public constructor of MyClass, which immediately throws a RuntimeException. This is typical Java behavior—constructors are always called when creating instances, and you cannot skip them with new.

Using Java Reflection

To better understand the difference, let’s compare what happens if you use traditional Java reflection to instantiate the same class:

import java.lang.reflect.Constructor;

public class ReflectionExample {

    public static class MyClass {

        private MyClass() {
            throw new RuntimeException("Constructor called!");
        }

        public void greet() {
            System.out.println("Greetings from MyClass!");
        }
    }

    public static void main(String[] args) throws Exception {
        // Will throw RuntimeException
        Constructor<MyClass> constructor = MyClass.class.getDeclaredConstructor();
        constructor.setAccessible(true);
        MyClass instance = constructor.newInstance();
        instance.greet();
    }
}

Even with reflection and access overrides, the constructor is still executed. This results in the same RuntimeException being thrown. Reflection gives you more flexibility than the new keyword, but it still respects constructor execution.

These examples demonstrate that both standard instantiation and reflection invoke constructors. If the constructor is private, throws an exception, or includes unwanted logic, these traditional techniques won’t help. Objenesis solves this problem by creating instances without triggering constructors which is a capability that proves essential in advanced use cases like mocking, serialization, and proxying.

5. Objenesis Strategies

Objenesis provides two main strategies:

  • ObjenesisStd – Uses the best strategy available for the current JVM.
  • ObjenesisSerializer – Simulates instantiation behavior similar to Java serialization.

Additionally, the Objenesis library includes ObjenesisHelper, a static utility class that streamlines the use of ObjenesisStd and ObjenesisSerializer. Let’s examine each in more detail.

5.1 ObjenesisStd

ObjenesisStd is the most commonly used strategy. It picks the most appropriate instantiator available on the JVM, typically relying on internal mechanisms such as sun.misc.Unsafe, reflection, or bytecode generation.

import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;


public class ObjenesisStdExample {

    public static class NoArgClass {

        private NoArgClass() {
            throw new RuntimeException("Constructor should not be called!");
        }

        public void sayHello() {
            System.out.println("Hello from NoArgClass");
        }
    }

    public static void main(String[] args) {
        Objenesis objenesis = new ObjenesisStd();
        NoArgClass instance = objenesis.newInstance(NoArgClass.class);
        instance.sayHello();
    }
}

Although the class has a private constructor that throws a RuntimeException, ObjenesisStd creates an instance without triggering it. This is ideal for use cases where calling the constructor is unnecessary or harmful.

5.2 ObjenesisSerializer

ObjenesisSerializer is designed to simulate the way objects are instantiated during Java deserialization. During Java’s native deserialization, constructors of subclasses are skipped and only the superclass with no-arg constructor is considered.

import java.io.Serializable;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisSerializer;

public class ObjenesisSerializerExample {

    public static class SerializableClass implements Serializable {

        private final String name;

        public SerializableClass() {
            this.name = "Default";
            System.out.println("Constructor called!");
        }

        public String getName() {
            return name;
        }
    }

    public static void main(String[] args) {
        Objenesis objenesis = new ObjenesisSerializer();
        SerializableClass instance = objenesis.newInstance(SerializableClass.class);
        System.out.println("Name: " + instance.getName()); // null
    }
}

The constructor is not called, so the final field name is never initialized. As a result, it returns null. This behavior is identical to how Java deserialization works under the hood, where constructors are bypassed.

When using ObjenesisSerializer to create an object, the target class must implement the Serializable interface. Failing to do so will typically result in a runtime exception, as ObjenesisSerializer relies on Java’s serialization mechanism to instantiate the object without invoking its constructor.

5.3 ObjenesisHelper

ObjenesisHelper is a static convenience class that provides a singleton-backed utility method for object creation. This is the simplest way to instantiate objects without worrying about creating an Objenesis instance yourself.

import org.objenesis.ObjenesisHelper;

public class ObjenesisHelperExample {

    public static class HiddenConstructor {

        private HiddenConstructor() {
            System.out.println("Constructor should not run!");
        }

        public void show() {
            System.out.println("Instance created via ObjenesisHelper!");
        }
    }

    public static void main(String[] args) {
        HiddenConstructor obj = ObjenesisHelper.newInstance(HiddenConstructor.class);
        obj.show();
    }
}

Similarly, we can use the serialization-based instantiation strategy with ObjenesisHelper, as shown below:

        HiddenConstructor obj = ObjenesisHelper.newSerializableInstance(HiddenConstructor.class);
        obj.show();

This examples shows how minimal the setup is using ObjenesisHelper. It is ideal for quick object instantiations, particularly in testing or prototype code.

6. Conclusion

In this article, we explored how Objenesis enables object instantiation in Java without invoking constructors which is a capability that proves invaluable in scenarios like testing, mocking, and serialization. We began by comparing traditional instantiation using the new keyword and reflection, both of which execute constructors and may cause unwanted side effects. We then introduced Objenesis and demonstrated its key strategies: ObjenesisStd, ObjenesisSerializer, and the convenient ObjenesisHelper.

Each strategy offers a different approach to creating instances, with ObjenesisSerializer specifically requiring the target class to implement Serializable.

7. Download the Source Code

This article provided an introduction to Java Objenesis.

Download
You can download the full source code of this example here: java objenesis introduction

Omozegie Aziegbe

Omos Aziegbe is a technical writer and web/application developer with a BSc in Computer Science and Software Engineering from the University of Bedfordshire. Specializing in Java enterprise applications with the Jakarta EE framework, Omos also works with HTML5, CSS, and JavaScript for web development. As a freelance web developer, Omos combines technical expertise with research and writing on topics such as software engineering, programming, web application development, computer science, and technology.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Back to top button