diff --git a/rules-java-ee/addon/src/main/java/org/jboss/windup/rules/apps/javaee/rules/DiscoverJPAAnnotationsRuleProvider.java b/rules-java-ee/addon/src/main/java/org/jboss/windup/rules/apps/javaee/rules/DiscoverJPAAnnotationsRuleProvider.java index be70a248a9..9c4e73016d 100644 --- a/rules-java-ee/addon/src/main/java/org/jboss/windup/rules/apps/javaee/rules/DiscoverJPAAnnotationsRuleProvider.java +++ b/rules-java-ee/addon/src/main/java/org/jboss/windup/rules/apps/javaee/rules/DiscoverJPAAnnotationsRuleProvider.java @@ -1,7 +1,11 @@ package org.jboss.windup.rules.apps.javaee.rules; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; import java.util.logging.Level; import java.util.logging.Logger; +import java.util.stream.Collectors; import org.jboss.windup.ast.java.data.TypeReferenceLocation; import org.jboss.windup.config.AbstractRuleProvider; @@ -12,12 +16,14 @@ import org.jboss.windup.config.operation.Iteration; import org.jboss.windup.config.operation.iteration.AbstractIterationOperation; import org.jboss.windup.config.phase.InitialAnalysisPhase; +import org.jboss.windup.graph.model.FileReferenceModel; import org.jboss.windup.graph.model.WindupVertexFrame; import org.jboss.windup.graph.service.GraphService; import org.jboss.windup.config.projecttraversal.ProjectTraversalCache; import org.jboss.windup.rules.apps.java.condition.JavaClass; import org.jboss.windup.rules.apps.java.model.AbstractJavaSourceModel; import org.jboss.windup.rules.apps.java.model.JavaClassModel; +import org.jboss.windup.rules.apps.java.model.JavaSourceFileModel; import org.jboss.windup.rules.apps.java.scan.ast.JavaTypeReferenceModel; import org.jboss.windup.rules.apps.java.scan.ast.annotations.JavaAnnotationListTypeValueModel; import org.jboss.windup.rules.apps.java.scan.ast.annotations.JavaAnnotationLiteralTypeValueModel; @@ -47,6 +53,7 @@ public class DiscoverJPAAnnotationsRuleProvider extends AbstractRuleProvider private static final String TABLE_ANNOTATIONS_LIST = "tableAnnotations"; private static final String NAMED_QUERY_LIST = "namedQuery"; private static final String NAMED_QUERIES_LIST = "namedQueries"; + private static final String DISCRIMINATOR_VALUE_LIST = "discriminatorValueList"; @Override public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) @@ -58,6 +65,7 @@ public Configuration getConfiguration(RuleLoaderContext ruleLoaderContext) .or(JavaClass.references("javax.persistence.Table").at(TypeReferenceLocation.ANNOTATION).as(TABLE_ANNOTATIONS_LIST)) .or(JavaClass.references("javax.persistence.NamedQuery").at(TypeReferenceLocation.ANNOTATION).as(NAMED_QUERY_LIST)) .or(JavaClass.references("javax.persistence.NamedQueries").at(TypeReferenceLocation.ANNOTATION).as(NAMED_QUERIES_LIST)) + .or(JavaClass.references("javax.persistence.DiscriminatorValue").at(TypeReferenceLocation.ANNOTATION).as(DISCRIMINATOR_VALUE_LIST)) ) .perform(Iteration.over(ENTITY_ANNOTATIONS).perform(new AbstractIterationOperation() { @@ -85,17 +93,59 @@ private String getAnnotationLiteralValue(JavaAnnotationTypeReferenceModel model, } } - private void extractEntityBeanMetadata(GraphRewrite event, JavaTypeReferenceModel entityTypeReference) + private JavaAnnotationTypeReferenceModel findTableAnnotation(GraphRewrite event, List sourceModels) + { + for (AbstractJavaSourceModel sourceModel : sourceModels) + { + Optional tableAnnotation = sourceModel.getAllTypeReferences().stream() + .filter(reference -> reference instanceof JavaAnnotationTypeReferenceModel) + .map(reference -> (JavaAnnotationTypeReferenceModel)reference) + .filter(annotationReference -> annotationReference.getResolvedSourceSnippit() != null && annotationReference.getResolvedSourceSnippit().contains("javax.persistence.Table")) + .findFirst(); + + if (tableAnnotation.isPresent()) + return tableAnnotation.get(); + else + return findTableAnnotation(event, getParentSourceFiles(event, sourceModel)); + } + return null; + } + + private List getParentSourceFiles(GraphRewrite event, AbstractJavaSourceModel sourceModel) + { + List result = new ArrayList<>(); + if (sourceModel == null) + return result; + + for (JavaClassModel javaClass : sourceModel.getJavaClasses()) + { + JavaClassModel parentClass = javaClass.getExtends(); + if (parentClass == null) + continue; + + AbstractJavaSourceModel parentJavaSourceModel = parentClass.getDecompiledSource(); + if (parentJavaSourceModel == null) + parentJavaSourceModel = parentClass.getOriginalSource(); + + if (parentJavaSourceModel == null) + { + LOG.warning("Could not find Java source for class: " + parentClass.getQualifiedName()); + continue; + } + + result.add(parentJavaSourceModel); + } + return result; + } + + private JavaAnnotationTypeReferenceModel findTableAnnotation(GraphRewrite event, JavaTypeReferenceModel entityTypeReference) { - LOG.log(Level.INFO, () -> "extractEntityBeanMetadata() with " + entityTypeReference.getDescription()); - entityTypeReference.getFile().setGenerateSourceReport(true); - JavaAnnotationTypeReferenceModel entityAnnotationTypeReference = (JavaAnnotationTypeReferenceModel) entityTypeReference; JavaAnnotationTypeReferenceModel tableAnnotationTypeReference = null; - final Iterable annotations_list = Variables.instance(event).findVariable(TABLE_ANNOTATIONS_LIST); - if (annotations_list != null) + final Iterable tableAnnotationList = Variables.instance(event).findVariable(TABLE_ANNOTATIONS_LIST); + if (tableAnnotationList != null) { - for (WindupVertexFrame annotationTypeReferenceBase : annotations_list) + for (WindupVertexFrame annotationTypeReferenceBase : tableAnnotationList) { JavaAnnotationTypeReferenceModel annotationTypeReference = (JavaAnnotationTypeReferenceModel) annotationTypeReferenceBase; if (annotationTypeReference.getFile().equals(entityTypeReference.getFile())) @@ -106,6 +156,22 @@ private void extractEntityBeanMetadata(GraphRewrite event, JavaTypeReferenceMode } } + if (tableAnnotationTypeReference == null) + { + AbstractJavaSourceModel sourceModel = entityTypeReference.getFile(); + tableAnnotationTypeReference = findTableAnnotation(event, getParentSourceFiles(event, sourceModel)); + } + + return tableAnnotationTypeReference; + } + + private void extractEntityBeanMetadata(GraphRewrite event, JavaTypeReferenceModel entityTypeReference) + { + LOG.log(Level.INFO, () -> "extractEntityBeanMetadata() with " + entityTypeReference.getDescription()); + entityTypeReference.getFile().setGenerateSourceReport(true); + JavaAnnotationTypeReferenceModel entityAnnotationTypeReference = (JavaAnnotationTypeReferenceModel) entityTypeReference; + JavaAnnotationTypeReferenceModel tableAnnotationTypeReference = findTableAnnotation(event, entityTypeReference); + JavaClassModel ejbClass = getJavaClass(entityTypeReference); String ejbName = getAnnotationLiteralValue(entityAnnotationTypeReference, "name"); diff --git a/rules-java-ee/tests/src/test/java/org/jboss/windup/rules/apps/javaee/tests/DiscoverJPAAnnotationsTest.java b/rules-java-ee/tests/src/test/java/org/jboss/windup/rules/apps/javaee/tests/DiscoverJPAAnnotationsTest.java new file mode 100644 index 0000000000..4baf882b6f --- /dev/null +++ b/rules-java-ee/tests/src/test/java/org/jboss/windup/rules/apps/javaee/tests/DiscoverJPAAnnotationsTest.java @@ -0,0 +1,75 @@ +package org.jboss.windup.rules.apps.javaee.tests; + +import org.apache.commons.io.FileUtils; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.windup.exec.WindupProcessor; +import org.jboss.windup.exec.configuration.WindupConfiguration; +import org.jboss.windup.graph.GraphContext; +import org.jboss.windup.graph.GraphContextFactory; +import org.jboss.windup.graph.model.ProjectModel; +import org.jboss.windup.graph.model.resource.FileModel; +import org.jboss.windup.graph.service.GraphService; +import org.jboss.windup.rules.apps.java.condition.SourceMode; +import org.jboss.windup.rules.apps.java.config.SourceModeOption; +import org.jboss.windup.rules.apps.javaee.AbstractTest; +import org.jboss.windup.rules.apps.javaee.model.EjbMessageDrivenModel; +import org.jboss.windup.rules.apps.javaee.model.JPAEntityModel; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.inject.Inject; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.UUID; + +/** + * @author Jesse Sightler + */ +@RunWith(Arquillian.class) +public class DiscoverJPAAnnotationsTest extends AbstractTest +{ + @Inject + private WindupProcessor processor; + + @Inject + private GraphContextFactory factory; + + @Test + public void testJPAMetadataExtraction() throws Exception + { + try (GraphContext context = factory.create(true)) + { + String inputPath = "src/test/resources/jpa"; + + Path outputPath = Paths.get(FileUtils.getTempDirectory().toString(), "windup_" + + UUID.randomUUID().toString()); + FileUtils.deleteDirectory(outputPath.toFile()); + Files.createDirectories(outputPath); + + WindupConfiguration windupConfiguration = new WindupConfiguration() + .setGraphContext(context); + windupConfiguration.addInputPath(Paths.get(inputPath)); + windupConfiguration.setOutputDirectory(outputPath); + windupConfiguration.setOptionValue(SourceModeOption.NAME, true); + processor.execute(windupConfiguration); + + GraphService jpaEntityModelService = new GraphService<>(context, JPAEntityModel.class); + int jpaEntitiesFound = 0; + for (JPAEntityModel jpaEntityModel : jpaEntityModelService.findAll()) + { + //Assert.assertEquals("ChatBeanDestination", msgDriven.getDestination().getJndiLocation()); + if (jpaEntityModel.getEntityName().equals("SubclassWithDiscriminator")) + Assert.assertEquals("SimpleEntityTable", jpaEntityModel.getTableName()); + else if (jpaEntityModel.getEntityName().equals("BaseEntity")) + Assert.assertEquals("SimpleEntityTable", jpaEntityModel.getTableName()); + else + Assert.fail("Unknown entity found with name: " + jpaEntityModel.getEntityName()); + + jpaEntitiesFound++; + } + Assert.assertEquals(2, jpaEntitiesFound); + } + } +} diff --git a/rules-java-ee/tests/src/test/resources/jpa/BaseEntity.java b/rules-java-ee/tests/src/test/resources/jpa/BaseEntity.java new file mode 100644 index 0000000000..0fbe3af2f3 --- /dev/null +++ b/rules-java-ee/tests/src/test/resources/jpa/BaseEntity.java @@ -0,0 +1,8 @@ +import javax.persistence.Entity; +import javax.persistence.Table; + +@Entity +@Table(name="SimpleEntityTable") +public class BaseEntity { + +} \ No newline at end of file diff --git a/rules-java-ee/tests/src/test/resources/jpa/SubclassWithDiscriminator.java b/rules-java-ee/tests/src/test/resources/jpa/SubclassWithDiscriminator.java new file mode 100644 index 0000000000..8c67c5c7d3 --- /dev/null +++ b/rules-java-ee/tests/src/test/resources/jpa/SubclassWithDiscriminator.java @@ -0,0 +1,10 @@ + +import javax.persistence.Entity; +import javax.persistence.Table; +import javax.persistence.NamedQuery; + +@Entity +@DiscriminatorValue("DV") +public class SubclassWithDiscriminator extends BaseEntity { + +} \ No newline at end of file diff --git a/rules-java/api/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/IndexJavaSourceFilesRuleProvider.java b/rules-java/api/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/IndexJavaSourceFilesRuleProvider.java index 3f98c307f4..9f8aaab712 100644 --- a/rules-java/api/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/IndexJavaSourceFilesRuleProvider.java +++ b/rules-java/api/src/main/java/org/jboss/windup/rules/apps/java/scan/provider/IndexJavaSourceFilesRuleProvider.java @@ -233,7 +233,7 @@ private void addParsedClassToFile(GraphRewrite event, EvaluationContext context, { Extendable extendable = (Extendable) javaSource; String superclassName = extendable.getSuperType(); - if (Strings.isNullOrEmpty(superclassName)) + if (!Strings.isNullOrEmpty(superclassName)) javaClassModel.setExtends(javaClassService.getOrCreatePhantom(superclassName)); }