diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Animal.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Animal.java new file mode 100644 index 0000000000000..405c85b0a603d --- /dev/null +++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Animal.java @@ -0,0 +1,16 @@ +package org.jboss.shamrock.example.jpa; + +/** + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +public class Animal { + private double weight; + + public double getWeight() { + return weight; + } + + public void setWeight(double weight) { + this.weight = weight; + } +} diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Customer.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Customer.java index a32b7b5c4d450..943d1e1536577 100644 --- a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Customer.java +++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Customer.java @@ -10,7 +10,7 @@ * @author Emmanuel Bernard emmanuel@hibernate.org */ @Entity -public class Customer { +public class Customer extends Human { @Id // no getter explicitly to test field only reflective access private Long id; diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Human.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Human.java new file mode 100644 index 0000000000000..487af53d5a6cf --- /dev/null +++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/Human.java @@ -0,0 +1,21 @@ +package org.jboss.shamrock.example.jpa; + +import javax.persistence.MappedSuperclass; + +/** + * Mapped superclass test + * + * @author Emmanuel Bernard emmanuel@hibernate.org + */ +@MappedSuperclass +public class Human extends Animal { + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestEndpoint.java b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestEndpoint.java index f175eb1c0c0bf..53e49d4e484dd 100644 --- a/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestEndpoint.java +++ b/examples/strict/src/main/java/org/jboss/shamrock/example/jpa/JPATestEndpoint.java @@ -17,9 +17,23 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IO makeSureEntitiesAreAccessibleViaReflection(resp); makeSureNonAnnotatedEmbeddableAreAccessibleViaReflection(resp); makeSureAnnotatedEmbeddableAreAccessibleViaReflection(resp); + makeSureClassAreAccessibleViaReflection("org.jboss.shamrock.example.jpa.Human", "Unable to enlist @MappedSuperclass", resp); + makeSureClassAreAccessibleViaReflection("org.jboss.shamrock.example.jpa.Animal", "Unable to enlist entity superclass", resp); resp.getWriter().write("OK"); } + private void makeSureClassAreAccessibleViaReflection(String className, String error, HttpServletResponse resp) throws IOException { + try { + className = getTrickedClassName(className); + + Class custClass = Class.forName(className); + Object instance = custClass.newInstance(); + } + catch (Exception e) { + resp.getWriter().write(error + " " + e.toString()); + } + } + private void makeSureEntitiesAreAccessibleViaReflection(HttpServletResponse resp) throws IOException { try { String className = getTrickedClassName("org.jboss.shamrock.example.jpa.Customer"); diff --git a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JPAAnnotationProcessor.java b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JPAAnnotationProcessor.java index 194ba9ca4fd9c..09d50d777d719 100644 --- a/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JPAAnnotationProcessor.java +++ b/jpa/deployment/src/main/java/org/jboss/shamrock/jpa/JPAAnnotationProcessor.java @@ -1,9 +1,6 @@ package org.jboss.shamrock.jpa; -import org.jboss.jandex.AnnotationInstance; -import org.jboss.jandex.AnnotationTarget; -import org.jboss.jandex.DotName; -import org.jboss.jandex.IndexView; +import org.jboss.jandex.*; import org.jboss.shamrock.deployment.ArchiveContext; import org.jboss.shamrock.deployment.ProcessorContext; import org.jboss.shamrock.deployment.ResourceProcessor; @@ -55,20 +52,20 @@ private void enlistReturnType(ProcessorContext processorContext, IndexView index if (annotations != null && annotations.size() > 0) { for (AnnotationInstance annotation : annotations) { AnnotationTarget target = annotation.target(); - String jpaClassName = null; + DotName jpaClassName = null; switch (target.kind()) { case FIELD: // TODO could fail if that's an array or a generic type - jpaClassName = target.asField().type().toString(); + jpaClassName = target.asField().type().name(); break; case METHOD: // TODO could fail if that's an array or a generic type - jpaClassName = target.asMethod().returnType().toString(); + jpaClassName = target.asMethod().returnType().name(); break; default: throw new IllegalStateException("[internal error] @Embedded placed on a unknown element: " + target); } - processorContext.addReflectiveClass(true, true, jpaClassName); + addClassHierarchyToReflectiveList(processorContext, index, jpaClassName); } } } @@ -77,13 +74,46 @@ private void enlistJPAModelClasses(DotName dotName, ProcessorContext processorCo Collection jpaAnnotations = index.getAnnotations(dotName); if (jpaAnnotations != null && jpaAnnotations.size() > 0) { for (AnnotationInstance annotation : jpaAnnotations) { - String entityClass = annotation.target().asClass().toString(); - processorContext.addReflectiveClass(true, true, entityClass); - template.addEntity(annotation.target().asClass().toString()); + DotName targetDotName = annotation.target().asClass().name(); + addClassHierarchyToReflectiveList(processorContext, index, targetDotName); + template.addEntity(targetDotName.toString()); } } } + /** + * Add the class to the reflective list with full method and field access. + * Add the superclasses recursively as well as the interfaces. + * + * TODO this approach fails if the Jandex index is not complete (e.g. misses somes interface or super types) + * TODO should we also return the return types of all methods and fields? It could container Enums for example. + */ + private void addClassHierarchyToReflectiveList(ProcessorContext processorContext, IndexView index, DotName className) { + // If type is not Object + // recursively add superclass and interfaces + if (className == null) { + // java.lang.Object + return; + } + ClassInfo classInfo = index.getClassByName(className); + if (classInfo == null) { + if (className == ClassType.OBJECT_TYPE.name()) { + return; + } + else { + throw new IllegalStateException("The Jandex index is not complete, missing: " + className.toString()); + } + } + // add class for reflection + processorContext.addReflectiveClass(true, true, className.toString()); + // add superclass recursively + addClassHierarchyToReflectiveList(processorContext, index, classInfo.superName()); + // add interfaces recursively + for (DotName interfaceDotName : classInfo.interfaceNames()) { + addClassHierarchyToReflectiveList(processorContext, index, interfaceDotName); + } + } + @Override public int getPriority() { // Because we are the best