diff --git a/ObjectLayout/pom.xml b/ObjectLayout/pom.xml index 504fb8e..48d3666 100644 --- a/ObjectLayout/pom.xml +++ b/ObjectLayout/pom.xml @@ -65,7 +65,7 @@ maven-surefire-plugin 2.12.4 - -Xmx1g + -Xmx1g -Xbootclasspath/a:${basedir}/target/classes false diff --git a/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java b/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java index 1445186..27a20c7 100644 --- a/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java +++ b/ObjectLayout/src/main/java/org/ObjectLayout/AbstractIntrinsicObjectModel.java @@ -45,6 +45,14 @@ Class getObjectClass() { return objectClass; } + Class getContainingClass() { + return containingClass; + } + + Field getField() { + return field; + } + private void sanityCheckAtModelConstruction() { if ((primitiveArrayModel != null) && !primitiveArrayModel._getArrayClass().equals(objectClass)) { @@ -141,7 +149,8 @@ final void _sanityCheckInstantiation(final Object containingObject) { try { if (field.get(containingObject) != null) { throw new IllegalStateException("Intrinsic object field \"" + field.getName() + - "\" in containing object is already initialized"); + "\" in containing object " + containingObject + " is already initialized to " + + field.get(containingObject)); } } catch (IllegalAccessException e) { throw new IllegalStateException(e); diff --git a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java index d1770bd..7b66a95 100644 --- a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java +++ b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjectModel.java @@ -34,9 +34,13 @@ final class IntrinsicObjectModel extends AbstractIntrinsicObjectModel { */ final T constructWithin(final Object containingObject) { try { + Constructor ctor = getObjectClass().getDeclaredConstructor(); + if (!ctor.isAccessible()) { + ctor.setAccessible(true); + } return instantiate( containingObject, - getObjectClass().getDeclaredConstructor(), + ctor, (Object[]) null ); } catch (NoSuchMethodException ex) { diff --git a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java index 13a074d..c5e32e1 100644 --- a/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java +++ b/ObjectLayout/src/main/java/org/ObjectLayout/IntrinsicObjects.java @@ -12,6 +12,9 @@ import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; +import sun.reflect.CallerSensitive; +import sun.reflect.Reflection; + /** * Intrinsic objects (declared with the {@link org.ObjectLayout.Intrinsic @Intrisic} annotation) may have * their layout within the containing object instance optimized by JDK implementations, such that access @@ -55,10 +58,24 @@ private IntrinsicObjects() { * @param containingObject The object instance that will contain this intrinsic object * @return A reference to the the newly constructed intrinsic object */ + @CallerSensitive + @SuppressWarnings("restriction") public static T constructWithin( final String fieldName, - final Object containingObject) { + final Object containingObject) throws IllegalArgumentException { + + // First we do some plausibility/security checks + Class caller = Reflection.getCallerClass(); + if (!containingObject.getClass().equals(caller)) + throw new IllegalArgumentException(); + IntrinsicObjectModel model = lookupModelFor(fieldName, containingObject); + + // Check if our caller is allowed to access the constructor. + // We wrap the "IllegalAccessException" in an unchecked "IllegalArgumentException" + // to avoid try/catch clauses around every call to "constructWithin" + sanityCheckAccessRights(caller, model.getObjectClass(), null); + return model.constructWithin(containingObject); } @@ -75,12 +92,26 @@ public static T constructWithin( * @param args the arguments to be used with the objectConstructor * @return A reference to the the newly constructed intrinsic object */ + @CallerSensitive + @SuppressWarnings("restriction") public static T constructWithin( final String fieldName, final Object containingObject, final Constructor objectConstructor, final Object... args) { + + // First we do some plausibility/security checks + Class caller = Reflection.getCallerClass(); + if (!containingObject.getClass().equals(caller)) + throw new IllegalArgumentException(); + IntrinsicObjectModel model = lookupModelFor(fieldName, containingObject); + + // Check if our caller is allowed to access the constructor. + // We wrap the "IllegalAccessException" in an unchecked "IllegalArgumentException" + // to avoid try/catch clauses around every call to "constructWithin" + sanityCheckAccessRights(caller, model.getObjectClass(), objectConstructor); + return model.constructWithin(containingObject, objectConstructor, args); } @@ -339,4 +370,20 @@ private static void sanityCheckAnnotation(Intrinsic intrinsicAnnotation, Cla } } } + + @SuppressWarnings("restriction") + private static void sanityCheckAccessRights(Class caller, Class field, Constructor ctor) { + // Check if our caller is allowed to access the constructor. + // We wrap the "IllegalAccessException" in an unchecked "IllegalArgumentException" + // to avoid try/catch clauses around every call to "constructWithin" + try { + if (ctor == null) + ctor = field.getDeclaredConstructor(); + Reflection.ensureMemberAccess(caller, field, ctor, ctor.getModifiers()); + } catch (IllegalAccessException e) { + throw new IllegalArgumentException(e); + } catch (NoSuchMethodException e) { + throw new IllegalArgumentException(e); + } + } }