Skip to content

Commit

Permalink
[jpa] Add support for superclasses and interfaces of entities
Browse files Browse the repository at this point in the history
  • Loading branch information
emmanuelbernard committed Aug 6, 2018
1 parent c7e79a9 commit 39f3922
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.jboss.shamrock.example.jpa;

/**
* @author Emmanuel Bernard [email protected]
*/
public class Animal {
private double weight;

public double getWeight() {
return weight;
}

public void setWeight(double weight) {
this.weight = weight;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* @author Emmanuel Bernard [email protected]
*/
@Entity
public class Customer {
public class Customer extends Human {
@Id
// no getter explicitly to test field only reflective access
private Long id;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.jboss.shamrock.example.jpa;

import javax.persistence.MappedSuperclass;

/**
* Mapped superclass test
*
* @author Emmanuel Bernard [email protected]
*/
@MappedSuperclass
public class Human extends Animal {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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);
}
}
}
Expand All @@ -77,13 +74,46 @@ private void enlistJPAModelClasses(DotName dotName, ProcessorContext processorCo
Collection<AnnotationInstance> 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
Expand Down

0 comments on commit 39f3922

Please sign in to comment.