Skip to content

Commit

Permalink
Refactor unsafe and class definition utils (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
henri-tremblay committed Jun 10, 2017
1 parent 6c033aa commit f10a6f1
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 64 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@
import org.objenesis.instantiator.ObjectInstantiator;
import org.objenesis.instantiator.annotations.Instantiator;
import org.objenesis.instantiator.annotations.Typology;
import org.objenesis.instantiator.util.ClassDefinitionUtils;

import static org.objenesis.instantiator.basic.ClassDefinitionUtils.*;
import static org.objenesis.instantiator.util.ClassDefinitionUtils.*;

/**
* This instantiator creates a class by dynamically extending it. It will skip the call to the parent constructor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@
import org.objenesis.instantiator.ObjectInstantiator;
import org.objenesis.instantiator.annotations.Instantiator;
import org.objenesis.instantiator.annotations.Typology;
import org.objenesis.instantiator.basic.ClassDefinitionUtils;
import org.objenesis.strategy.PlatformDescription;
import org.objenesis.instantiator.util.ClassDefinitionUtils;

import static org.objenesis.instantiator.basic.ClassDefinitionUtils.*;
import static org.objenesis.instantiator.util.ClassDefinitionUtils.*;

/**
* This instantiator will correctly bypass the constructors by instantiating the class using the default
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@
import org.objenesis.instantiator.ObjectInstantiator;
import org.objenesis.instantiator.annotations.Instantiator;
import org.objenesis.instantiator.annotations.Typology;
import org.objenesis.instantiator.util.UnsafeUtils;

import java.lang.reflect.Field;

/**
* Instantiates an object, WITHOUT calling it's constructor, using
* sun.misc.Unsafe.allocateInstance(). Unsafe and its methods are implemented by most
* {@code sun.misc.Unsafe.allocateInstance()}. Unsafe and its methods are implemented by most
* modern JVMs.
*
* @author Henri Tremblay
Expand All @@ -35,24 +36,11 @@
@Instantiator(Typology.STANDARD)
public class UnsafeFactoryInstantiator<T> implements ObjectInstantiator<T> {

private static Unsafe unsafe;
private final Unsafe unsafe;
private final Class<T> type;

public UnsafeFactoryInstantiator(Class<T> type) {
if (unsafe == null) {
Field f;
try {
f = Unsafe.class.getDeclaredField("theUnsafe");
} catch (NoSuchFieldException e) {
throw new ObjenesisException(e);
}
f.setAccessible(true);
try {
unsafe = (Unsafe) f.get(null);
} catch (IllegalAccessException e) {
throw new ObjenesisException(e);
}
}
this.unsafe = UnsafeUtils.getUnsafe(); // retrieve it to fail right away at instantiator creation if not there
this.type = type;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,35 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.objenesis.instantiator.basic;

/*
* Copyright 2003,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.objenesis.instantiator.util;

import org.objenesis.ObjenesisException;

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;

import sun.misc.Unsafe;

/**
* Helper class for ProxyObjectInstantiator. We can see the details of a class specification
* <a href="http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html">here</a>
Expand Down Expand Up @@ -86,7 +72,7 @@ public final class ClassDefinitionUtils {

private ClassDefinitionUtils() { }

private static Method DEFINE_CLASS;
// private static Method DEFINE_CLASS;
private static final ProtectionDomain PROTECTION_DOMAIN;

static {
Expand All @@ -95,26 +81,6 @@ public ProtectionDomain run() {
return ClassDefinitionUtils.class.getProtectionDomain();
}
});

AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
Class<?> loader = Class.forName("java.lang.ClassLoader"); // JVM crash w/o this
DEFINE_CLASS = loader.getDeclaredMethod("defineClass",
new Class[]{ String.class,
byte[].class,
Integer.TYPE,
Integer.TYPE,
ProtectionDomain.class });
DEFINE_CLASS.setAccessible(true);
} catch (ClassNotFoundException e) {
throw new ObjenesisException(e);
} catch (NoSuchMethodException e) {
throw new ObjenesisException(e);
}
return null;
}
});
}

/**
Expand All @@ -131,8 +97,7 @@ public Object run() {
@SuppressWarnings("unchecked")
public static <T> Class<T> defineClass(String className, byte[] b, ClassLoader loader)
throws Exception {
Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), PROTECTION_DOMAIN };
Class<T> c = (Class<T>) DEFINE_CLASS.invoke(loader, args);
Class<T> c = (Class<T>) UnsafeUtils.getUnsafe().defineClass(className, b, 0, b.length, loader, PROTECTION_DOMAIN);
// Force static initializers to run.
Class.forName(className, true, loader);
return c;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright 2006-2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.objenesis.instantiator.util;

import java.lang.reflect.Field;

import org.objenesis.ObjenesisException;

import sun.misc.Unsafe;

/**
* Helper class basically allowing to get access to {@code sun.misc.Unsafe}
*
* @author Henri Tremblay
*/
public final class UnsafeUtils {

private static final Unsafe unsafe;

static {
Field f;
try {
f = Unsafe.class.getDeclaredField("theUnsafe");
} catch (NoSuchFieldException e) {
throw new ObjenesisException(e);
}
f.setAccessible(true);
try {
unsafe = (Unsafe) f.get(null);
} catch (IllegalAccessException e) {
throw new ObjenesisException(e);
}
}

private UnsafeUtils() {}

public static Unsafe getUnsafe() {
return unsafe;
}
}
2 changes: 1 addition & 1 deletion main/src/test/java/org/objenesis/ClassReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
import java.util.Arrays;

import static org.junit.Assert.*;
import static org.objenesis.instantiator.basic.ClassDefinitionUtils.*;
import static org.objenesis.instantiator.util.ClassDefinitionUtils.*;

/**
* @author Henri Tremblay
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ public class MagicInstantiatorTest {
public void before() {
// I know it works on Hotspot and OpenJDK. Before JDK 9. Not sure on others
assumeTrue((PlatformDescription.isThisJVM(PlatformDescription.HOTSPOT) || PlatformDescription.isThisJVM(PlatformDescription.OPENJDK))
&& !PlatformDescription.SPECIFICATION_VERSION.equals("9"));
&& !PlatformDescription.SPECIFICATION_VERSION.equals("9")
);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.objenesis.instantiator.basic;
package org.objenesis.instantiator.util;

import org.junit.Test;
import org.objenesis.instantiator.util.ClassDefinitionUtils;

import static org.junit.Assert.*;

Expand Down

0 comments on commit f10a6f1

Please sign in to comment.