Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Paradox instantiation

Tags:

java

Any thoughts to instantiate Paradox class without modifying the class itself?

public final class Paradox {
    private final Paradox paradox;

    public Paradox(Paradox paradox) {
        this.paradox = paradox;
        if (this.paradox == null) throw new InceptionException();
    }

    private static class InceptionException extends RuntimeException {
        public InceptionException() {
            super("Paradox requires an instance of paradox to be instantiated");
        }
    }
}
like image 885
Víctor Albertos Avatar asked Aug 31 '15 19:08

Víctor Albertos


2 Answers

As already pointed out in the comments: It is possible with the sun.misc.Unsafe class:

import java.lang.reflect.Constructor;

import sun.misc.Unsafe;

public class ParadoxTest
{
    public static void main(String[] args) throws Exception
    {
        Constructor<Unsafe> unsafeConstructor = 
            Unsafe.class.getDeclaredConstructor();
        unsafeConstructor.setAccessible(true);
        Unsafe unsafe = unsafeConstructor.newInstance();
        Paradox paradox = (Paradox) unsafe.allocateInstance(Paradox.class);
        System.out.println("This is paradox: "+paradox);
    }
}

Alternatively, one could use the JNI function AllocObject, which also allocates a new object without invoking any of the constructors.

EDIT: Someone found another solution - without sun.misc.Unsafe!

EDIT2: But note that this solution also uses Sun proprietary classes, which are not part of the public API, and so this solution is still not portable and should not be used in production code!

import java.lang.reflect.Constructor;

import sun.reflect.ReflectionFactory;

public class AnotherParadoxTest
{
    public static void main(String[] args) throws Exception
    {
        ReflectionFactory rf = ReflectionFactory.getReflectionFactory();
        Constructor<?> declaredConstructor = 
            Object.class.getDeclaredConstructor();
        Constructor<?> constructor = rf.newConstructorForSerialization(
            Paradox.class, declaredConstructor);
        Paradox paradox = (Paradox) constructor.newInstance();
        System.out.println("This is paradox: "+paradox);
    }
    
}

EDIT3: Just for completeness, and per request in the comments: The JNI-based solution

As mentioned above, the JNI function AllocObject does not call a constructor, so this may also be used to instantiate such an object. This is the calling class which contains the native method and loads the native library:

public class ParadoxTestWithJni
{
    static
    {
        System.loadLibrary("Paradox");
    }
    public static void main(String[] args)
    {
        Paradox paradox = createParadox();
        System.out.println("This is paradox: "+paradox);
    }

    private native static Paradox createParadox();
}

The header ParadoxTestWithJni.h that was created for this class with javah:

#include <jni.h>
#ifndef _Included_ParadoxTestWithJni
#define _Included_ParadoxTestWithJni
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jobject JNICALL Java_ParadoxTestWithJni_createParadox
  (JNIEnv *, jclass);
#ifdef __cplusplus
}
#endif
#endif

The corresponding implementation ... "where the magic happens":

#include "ParadoxTestWithJni.h"
JNIEXPORT jobject JNICALL Java_ParadoxTestWithJni_createParadox
(JNIEnv *env, jclass c)
{
    jclass paradoxClass = env->FindClass("Paradox");
    jobject paradox = env->AllocObject(paradoxClass);
    return paradox;
}
like image 143
Marco13 Avatar answered Nov 19 '22 03:11

Marco13


Let's say that the Paradox class is in a package test, like this (of course it could be in the default package, but the question doesn't really specify it):

package test;

public final class Paradox {
    private final Paradox paradox;

    public Paradox(Paradox paradox) {
        this.paradox = paradox;
        if (this.paradox == null) throw new InceptionException();
    }

    private static class InceptionException extends RuntimeException {
        public InceptionException() {
            super("Paradox requires an instance of paradox to be instantiated");
        }
    }
}

An XML representation, if it had been serialized by XStream, of the class would look like this:

<test.Paradox/>

Given this XML, it can be deserialized without calling the constructor:

public static void main(String[] args) {
    XStream xstream = new XStream(new DomDriver());
    Paradox paradoxFromXml = (Paradox) xstream.fromXML("<test.Paradox/>");
    System.out.println(paradoxFromXml);
}

The output is:

test.Paradox@72d818d1

This answer takes advantage of the fact that XStream doesn't call a constructor during deserialization, as stated in their FAQ:

XStream is not calling the default constructor during deserialization.
This is, in fact, the same case as above. XStream uses the same mechanism as the JDK serialization. When using the enhanced mode with the optimized reflection API, it does not invoke the default constructor. The solution is to implement the readResolve or readObject as demonstrated with the last question.

So, by utilizing the straightforward XML representation XStream has by default, the class can be initialized through deserialization, despite the fact that the class is not serializable.

As a further explanation to this, XStream in this case probably initializes the class by using SunLimitedUnsafeReflectionProvider or SunUnsafeReflectionProvider, which internally uses sun.misc.Unsafe, as their Javadoc states (thanks to marco13 for pointing this out):

SunLimitedUnsafeReflectionProvider:

/**
 * Instantiates a new object bypassing the constructor using undocumented internal JDK features.
 * <p>
 * The code in the constructor will never be executed and parameters do not have to be known. This is the same method
 * used by the internals of standard Java serialization, but relies on internal code (sun.misc.Unsafe) that may not be
 * present on all JVMs.
 * <p>
 * <p>
 * The implementation will use standard Java functionality to write any fields. This requires Java 5 as minimum runtime
 * and is used as fallback on platforms that do not provide the complete implementation level for the internals (like
 * Dalvik).
 * <p>
 * 
 * @author J&ouml;rg Schaible
 * @author Joe Walnes
 * @author Brian Slesinsky
 * @since 1.4.7
 */

SunUnsafeReflectionProvider:

/**
 * Instantiates a new object bypassing the constructor using undocumented internal JDK features.
 * <p>
 * The code in the constructor will never be executed and parameters do not have to be known. This is the same method
 * used by the internals of standard Java serialization, but relies on internal code (sun.misc.Unsafe) that may not be
 * present on all JVMs.
 * <p>
 * <p>
 * The implementation will use the same internals to write into fields. This is a lot faster and was additionally the
 * only possibility to set final fields prior to Java 5.
 * <p>
 *
 * @author Joe Walnes
 * @author Brian Slesinsky
 * @author J&ouml;rg Schaible
 * @since 1.4.7
 */

In all honesty, I just remembered that XStream had the capabilities to initialize objects without calling constructors, without having the time at the moment of answering the question to dig further into it.

like image 13
Magnilex Avatar answered Nov 19 '22 01:11

Magnilex