/* * Written by Gil Tene, and released to the public domain, * as explained at http://creativecommons.org/publicdomain/zero/1.0/ */ package org.ObjectLayoutApiTests; import org.ObjectLayout.Intrinsic; import org.ObjectLayout.IntrinsicObjects; import org.junit.Test; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Constructor; import static java.lang.Long.valueOf; import static org.hamcrest.CoreMatchers.is; import static org.junit.Assert.assertThat; public class IntrinsticObjectTest { @Test public void shouldConstructLine() throws NoSuchMethodException { Line line = new Line(); Point endPoint1 = line.getEndPoint1(); Point endPoint2 = line.getEndPoint2(); assertThat(valueOf(endPoint1.getX()), is(0L)); assertThat(valueOf(endPoint1.getY()), is(0L)); assertThat(valueOf(endPoint2.getX()), is(0L)); assertThat(valueOf(endPoint2.getY()), is(0L)); Line line2 = new Line(1, 2, 3, 4); endPoint1 = line2.getEndPoint1(); endPoint2 = line2.getEndPoint2(); assertThat(valueOf(endPoint1.getX()), is(1L)); assertThat(valueOf(endPoint1.getY()), is(2L)); assertThat(valueOf(endPoint2.getX()), is(3L)); assertThat(valueOf(endPoint2.getY()), is(4L)); Line line3 = new Line(line2); endPoint1 = line3.getEndPoint1(); endPoint2 = line3.getEndPoint2(); assertThat(valueOf(endPoint1.getX()), is(1L)); assertThat(valueOf(endPoint1.getY()), is(2L)); assertThat(valueOf(endPoint2.getX()), is(3L)); assertThat(valueOf(endPoint2.getY()), is(4L)); } @Test public void shouldSucceedInAccessFakeIntrinsic() throws NoSuchMethodException { Line line = new Line(); Point endPoint1 = line.getEndPoint1(); Point endPoint2 = line.getEndPoint2(); assertThat(valueOf(endPoint1.getX()), is(0L)); assertThat(valueOf(endPoint1.getY()), is(0L)); assertThat(valueOf(endPoint2.getX()), is(0L)); assertThat(valueOf(endPoint2.getY()), is(0L)); // Make a fake intrinsic Point in the line: Point badPoint = new Point(0, 0); Line line2 = new Line(line, badPoint); // Access should still work (may be slower, but should work): endPoint1 = line2.getEndPoint1(); endPoint2 = line2.getEndPoint2(); assertThat(valueOf(endPoint1.getX()), is(0L)); assertThat(valueOf(endPoint1.getY()), is(0L)); assertThat(valueOf(endPoint2.getX()), is(0L)); assertThat(valueOf(endPoint2.getY()), is(0L)); } /** * BadContainerSuperPoint: Wrong size init for intrinsic object member */ static class BadContainerSuperPoint { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); static final Constructor<SuperPoint> constructor; static { try { constructor = SuperPoint.class.getConstructor(); } catch (NoSuchMethodException ex) { throw new RuntimeException(ex); } } Object o = constructor; @SuppressWarnings("unchecked") @Intrinsic private final Point intrinsicPoint = IntrinsicObjects.constructWithin(lookup, "intrinsicPoint", this, (Constructor<Point>) o, (Object[]) null); Point getPoint() { return intrinsicPoint; } } @Test(expected = IllegalArgumentException.class) public void testBadContainerSuperPoint() throws NoSuchMethodException { BadContainerSuperPoint bad = new BadContainerSuperPoint(); bad.getPoint().getX(); } /** * BadContainerNonPrivate: non @Intrinsic intrinsic object member construction attempt */ static class BadContainerNonIntrinsic { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); private final Point intrinsicPoint = IntrinsicObjects.constructWithin(lookup, "intrinsicPoint", this); Point getPoint() { return intrinsicPoint; } } @Test(expected = IllegalArgumentException.class) public void testBadContainerNonIntrinsic() throws NoSuchMethodException { BadContainerNonIntrinsic bad = new BadContainerNonIntrinsic(); bad.getPoint().getX(); } /** * BadContainerNonPrivate: non private intrinsic object member */ static class BadContainerNonPrivate { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); @Intrinsic final Point intrinsicPoint = IntrinsicObjects.constructWithin(lookup, "intrinsicPoint", this); Point getPoint() { return intrinsicPoint; } } @Test(expected = IllegalArgumentException.class) public void testBadContainerNonPrivate() throws NoSuchMethodException { BadContainerNonPrivate bad = new BadContainerNonPrivate(); bad.getPoint().getX(); } /** * BadContainerNonFinal: non final intrinsic object member */ static class BadContainerNonFinal { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); @Intrinsic private Point intrinsicPoint = IntrinsicObjects.constructWithin(lookup, "intrinsicPoint", this); Point getPoint() { return intrinsicPoint; } } @Test(expected = IllegalArgumentException.class) public void testBadContainerNonFinal() throws NoSuchMethodException { BadContainerNonFinal bad = new BadContainerNonFinal(); bad.getPoint().getX(); } /** * BadContainerNullMember: null intrinsic object member */ static class BadContainerNullMember { @Intrinsic private final Point intrinsicPoint = null; Point getPoint() { return intrinsicPoint; } } @Test(expected = NullPointerException.class) public void testBadContainerNullMember() throws NoSuchMethodException { BadContainerNullMember bad = new BadContainerNullMember(); bad.getPoint().getX(); } /** * BadContainerOtherMemberIsNull: Badly initialized but not accessed member (should still work, may be slower). */ static class BadContainerOtherMemberIsNull { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); @Intrinsic private final Point intrinsicPoint1 = IntrinsicObjects.constructWithin(lookup, "intrinsicPoint1", this); @Intrinsic private final Point intrinsicPoint2 = null; Point getPoint() { return intrinsicPoint1; } } @Test public void testBadContainerOtherMemberIsNull() throws NoSuchMethodException { BadContainerOtherMemberIsNull bad = new BadContainerOtherMemberIsNull(); bad.getPoint().getX(); } /** * BadContainerCrossAssignment: Badly initialized but not accessed member (should still work, may be slower). */ static class BadContainerCrossAssignment { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); @Intrinsic private final Point intrinsicPoint1 = IntrinsicObjects.constructWithin(lookup, "intrinsicPoint1", this); @Intrinsic private final Point intrinsicPoint2 = intrinsicPoint1; Point getPoint() { return intrinsicPoint1; } } @Test public void testBadContainerCrossAssignment() throws NoSuchMethodException { BadContainerCrossAssignment bad = new BadContainerCrossAssignment(); bad.getPoint().getX(); } /** * BadContainerFieldName: Badly initialized member (using field name that doesn't exist). */ static class BadContainerFieldName { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); @Intrinsic private final Point intrinsicPoint = IntrinsicObjects.constructWithin(lookup, "someObject", this); Point getPoint() { return intrinsicPoint; } } @Test(expected = IllegalArgumentException.class) public void testBadContainerFieldName() throws NoSuchMethodException { BadContainerFieldName bad = new BadContainerFieldName(); bad.getPoint().getX(); } /** * BadContainerFieldName: Badly initialized member (using field name that is not assignable from object). */ static class BadContainerFieldType { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); @Intrinsic private final Point intrinsicPoint = IntrinsicObjects.constructWithin(lookup, "someObject", this); @Intrinsic private final long someObject = 0; Point getPoint() { return intrinsicPoint; } } @Test(expected = IllegalArgumentException.class) public void testBadContainerFieldType() throws NoSuchMethodException { BadContainerFieldType bad = new BadContainerFieldType(); bad.getPoint().getX(); } /** * A simple x,y point class to be used as an element in various other examples. * */ public static class Point { private long x; private long y; public Point() { } public Point(final long x, final long y) { this.x = x; this.y = y; } public Point(final Point source) { this(source.x, source.y); } public long getX() { return x; } public void setX(final long x) { this.x = x; } public long getY() { return y; } public void setY(final long y) { this.y = y; } public void set(final long x, final long y) { this.x = x; this.y = y; } } public static class SuperPoint extends Point { private long z; public SuperPoint() { } public SuperPoint(final long x, final long y, final long z) { super(x, y); this.z = z; } public SuperPoint(final SuperPoint source) { this(source.getX(), source.getY(), source.z); } public long getZ() { return z; } public void setZ(final long z) { this.z = z; } } /** * A simple Line class example with two intrinsic Point end point objects. * * This class demonstrates * */ private static class Line { static final MethodHandles.Lookup lookup = MethodHandles.lookup(); /** * Simple Intrinsic Object declaration and initialization: */ @Intrinsic private final Point endPoint1 = IntrinsicObjects.constructWithin(lookup, "endPoint1", this); /** * Declaration of an Intrinsic Object that will be initialized later during construction or other init code: */ @Intrinsic private final Point endPoint2; public Line() { this(0, 0, 0, 0); } public Line(final long x1, final long y1, long x2, long y2) { /** * Construction-time Initialization of IntrinsicObject: */ this.endPoint2 = IntrinsicObjects.constructWithin(lookup, "endPoint2", this, xy_constructor, x2, y2); /** * Access to IntrinsicObject within constructor: */ this.endPoint1.set(x1, y1); } /** * A bad Line() constructor, initializes an intrinsic member to * with the value of an externally supplied parameter. * * @param source * @param endPoint2 */ public Line(final Line source, final Point endPoint2) { this.endPoint2 = endPoint2; } public Line(final Line source) { this(source.endPoint1.getX(), source.endPoint1.getY(), source.endPoint2.getX(), source.endPoint2.getY()); } public Point getEndPoint1() { return endPoint1; } public Point getEndPoint2() { return endPoint2; } static final Constructor<Point> xy_constructor; static { try { xy_constructor = Point.class.getConstructor(new Class[] {long.class, long.class}); } catch (NoSuchMethodException ex) { throw new RuntimeException(ex); } } } }