From 6425ee9eaaf26c25230541bb1e05ac6b0ca7c6c4 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Mon, 8 Apr 2024 22:06:36 +0200 Subject: [PATCH 01/14] Update versions for feature branch --- annotationwrapper/api/pom.xml | 2 +- annotationwrapper/integrationtest/pom.xml | 2 +- annotationwrapper/pom.xml | 2 +- annotationwrapper/processor/pom.xml | 2 +- common/pom.xml | 2 +- compilermessages/api/pom.xml | 2 +- compilermessages/integrationtest/pom.xml | 2 +- compilermessages/pom.xml | 2 +- compilermessages/processor/pom.xml | 2 +- cute/pom.xml | 2 +- example/example-annotationprocessor/pom.xml | 2 +- example/example-annotations/pom.xml | 2 +- example/example-usecase/pom.xml | 2 +- example/pom.xml | 2 +- extensions/java9/pom.xml | 2 +- extensions/pom.xml | 2 +- pom.xml | 2 +- templating/pom.xml | 2 +- tools/pom.xml | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/annotationwrapper/api/pom.xml b/annotationwrapper/api/pom.xml index 0680b126..4119864a 100644 --- a/annotationwrapper/api/pom.xml +++ b/annotationwrapper/api/pom.xml @@ -8,7 +8,7 @@ io.toolisticon.aptk aptk-annotationwrapper-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-annotationwrapper-api diff --git a/annotationwrapper/integrationtest/pom.xml b/annotationwrapper/integrationtest/pom.xml index 454c3335..c7a5d39c 100644 --- a/annotationwrapper/integrationtest/pom.xml +++ b/annotationwrapper/integrationtest/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.aptk aptk-annotationwrapper-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-annotationwrapper-integrationTest diff --git a/annotationwrapper/pom.xml b/annotationwrapper/pom.xml index 5068d84e..e4fc4c27 100644 --- a/annotationwrapper/pom.xml +++ b/annotationwrapper/pom.xml @@ -11,7 +11,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT diff --git a/annotationwrapper/processor/pom.xml b/annotationwrapper/processor/pom.xml index 5f2055b9..df8ff143 100644 --- a/annotationwrapper/processor/pom.xml +++ b/annotationwrapper/processor/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.aptk aptk-annotationwrapper-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-annotationwrapper-processor diff --git a/common/pom.xml b/common/pom.xml index 0b3c3313..cd1d67d8 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-common diff --git a/compilermessages/api/pom.xml b/compilermessages/api/pom.xml index 4173655a..ff64ba8a 100644 --- a/compilermessages/api/pom.xml +++ b/compilermessages/api/pom.xml @@ -8,7 +8,7 @@ io.toolisticon.aptk aptk-compilermessages-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-compilermessages-api diff --git a/compilermessages/integrationtest/pom.xml b/compilermessages/integrationtest/pom.xml index 1eb7e855..51b56485 100644 --- a/compilermessages/integrationtest/pom.xml +++ b/compilermessages/integrationtest/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.aptk aptk-compilermessages-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-compilermessages-integrationTest diff --git a/compilermessages/pom.xml b/compilermessages/pom.xml index 265d741c..ce55730c 100644 --- a/compilermessages/pom.xml +++ b/compilermessages/pom.xml @@ -11,7 +11,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT diff --git a/compilermessages/processor/pom.xml b/compilermessages/processor/pom.xml index b3818320..3df8978b 100644 --- a/compilermessages/processor/pom.xml +++ b/compilermessages/processor/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.aptk aptk-compilermessages-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-compilermessages-processor diff --git a/cute/pom.xml b/cute/pom.xml index 5ea81dbb..ec79516d 100644 --- a/cute/pom.xml +++ b/cute/pom.xml @@ -8,7 +8,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-cute diff --git a/example/example-annotationprocessor/pom.xml b/example/example-annotationprocessor/pom.xml index f7e345ec..b54fd042 100644 --- a/example/example-annotationprocessor/pom.xml +++ b/example/example-annotationprocessor/pom.xml @@ -8,7 +8,7 @@ io.toolisticon.aptk aptk-example-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-example-annotationprocessor diff --git a/example/example-annotations/pom.xml b/example/example-annotations/pom.xml index a77b9fc6..5af61772 100644 --- a/example/example-annotations/pom.xml +++ b/example/example-annotations/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk aptk-example-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-example-annotations diff --git a/example/example-usecase/pom.xml b/example/example-usecase/pom.xml index 2de146b6..8e24038d 100644 --- a/example/example-usecase/pom.xml +++ b/example/example-usecase/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk aptk-example-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-example-usecase diff --git a/example/pom.xml b/example/pom.xml index 63ce5bc6..a5069553 100644 --- a/example/pom.xml +++ b/example/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-example-parent diff --git a/extensions/java9/pom.xml b/extensions/java9/pom.xml index b856cd97..17b2be14 100644 --- a/extensions/java9/pom.xml +++ b/extensions/java9/pom.xml @@ -8,7 +8,7 @@ io.toolisticon.aptk extension-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-tools-java9 diff --git a/extensions/pom.xml b/extensions/pom.xml index 5e41e6c1..ec52b04a 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT extension-parent diff --git a/pom.xml b/pom.xml index 78407101..fb7101ce 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT pom aptk-parent diff --git a/templating/pom.xml b/templating/pom.xml index 64951be1..8d0fe47c 100644 --- a/templating/pom.xml +++ b/templating/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-templating diff --git a/tools/pom.xml b/tools/pom.xml index f7164e7a..8f02f7aa 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -8,7 +8,7 @@ io.toolisticon.aptk aptk-parent - 0.24.1-SNAPSHOT + 0.24.1-148_records-SNAPSHOT aptk-tools From f7e45bcd5de52f62eceadc91c75dec774f644810 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Tue, 9 Apr 2024 12:02:36 +0200 Subject: [PATCH 02/14] [#148] Add proper support for records introduced with Java 16 --- .github/workflows/release.yml | 4 +- extensions/java16/pom.xml | 93 ++++++++++ .../RecordComponentElementWrapper.java | 72 ++++++++ .../aptk/tools/wrapper/Java16Tests.java | 165 ++++++++++++++++++ extensions/pom.xml | 12 ++ pom.xml | 16 +- tools/pom.xml | 5 +- .../io/toolisticon/aptk/tools/BeanUtils.java | 6 +- .../toolisticon/aptk/tools/ElementUtils.java | 45 ++++- .../tools/ProcessingEnvironmentUtils.java | 11 -- .../tools/corematcher/AptkCoreMatchers.java | 33 ++-- .../CoreMatcherValidationMessages.java | 3 + .../tools/matcher/impl/IsRecordMatcher.java | 19 ++ .../aptk/tools/wrapper/ElementWrapper.java | 27 +++ .../toolisticon/aptk/tools/BeanUtilsTest.java | 7 +- 15 files changed, 477 insertions(+), 41 deletions(-) create mode 100644 extensions/java16/pom.xml create mode 100644 extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java create mode 100644 extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java create mode 100644 tools/src/main/java/io/toolisticon/aptk/tools/matcher/impl/IsRecordMatcher.java diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d056bb3..e3e3739c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -28,10 +28,10 @@ jobs: run: echo ${{ secrets.GPG_SECRET_KEYS }} | base64 --decode | gpg --import --no-tty --batch --yes # Setup JDK and Maven - - name: Set up JDK 9 + - name: Set up JDK 17 uses: actions/setup-java@v1 with: - java-version: 9 + java-version: 17 server-id: sonatype-nexus-staging server-username: OSS_CENTRAL_USERNAME # env variable for Maven Central server-password: OSS_CENTRAL_PASSWORD # env variable for Maven Central diff --git a/extensions/java16/pom.xml b/extensions/java16/pom.xml new file mode 100644 index 00000000..814be0bb --- /dev/null +++ b/extensions/java16/pom.xml @@ -0,0 +1,93 @@ + + 4.0.0 + + aptk-tools-java16 + jar + + + io.toolisticon.aptk + extension-parent + 0.24.1-148_records-SNAPSHOT + + + aptk-tools-java16 + + + + + + + io.toolisticon.aptk + aptk-tools-java9 + + + + io.toolisticon.aptk + aptk-tools + + + + + + + + + + + maven-enforcer-plugin + + + enforce + + enforce + + + + + [3.0.4,) + + + 9 + + + false + + * + + + io.toolisticon.aptk:aptk-tools:* + io.toolisticon.aptk:aptk-tools-java9:* + *:*:*:*:test:* + *:*:*:*:provided:* + + + + + + + + + + maven-compiler-plugin + + 16 + 16 + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + true + + + + + + + + + + diff --git a/extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java b/extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java new file mode 100644 index 00000000..30cb7233 --- /dev/null +++ b/extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java @@ -0,0 +1,72 @@ +package io.toolisticon.aptk.tools.wrapper; + +import javax.lang.model.element.Element; +import javax.lang.model.element.RecordComponentElement; +import javax.lang.model.element.TypeElement; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Wrapper class for RecordComponentElementWrapper. + */ +public class RecordComponentElementWrapper extends ElementWrapper { + private RecordComponentElementWrapper(RecordComponentElement recordComponentElement) { + super(recordComponentElement); + } + + /** + * Gets the enclosing records TypeElement + * @return the wrapped enclosing records TypeElement + */ + public TypeElementWrapper getEnclosingRecordTypeElement() { + return TypeElementWrapper.wrap((TypeElement) element.getEnclosingElement()); + } + + /** + * Wraps the getAccessor method, but returns a ExecutableElementWrapper + * @return the accessors wrapped ExecutableElement + */ + public ExecutableElementWrapper getAccessor() { + return ExecutableElementWrapper.wrap(element.getAccessor()); + } + + /** + * Gets the record components for a TypeElementWrapper. + * @param typeElement the type element wrapper to get the record components for + * @return A list containing the wrapped RecordComponentElement if they exist, otherwise an empty list. + */ + public static List getRecordComponents(TypeElementWrapper typeElement) { + if (typeElement == null) { + return Collections.EMPTY_LIST; + } + return getRecordComponents(typeElement.unwrap()); + } + + /** + * Gets the record components for a TypeElement. + * @param typeElement the type element wrapper to get the record components for + * @return A list containing the wrapped RecordComponentElement if they exist, otherwise an empty list. + */ + public static List getRecordComponents(TypeElement typeElement) { + if (typeElement == null) { + return Collections.EMPTY_LIST; + } + + return typeElement.getRecordComponents().stream().map(RecordComponentElementWrapper::wrap).toList(); + + } + + public static RecordComponentElementWrapper toRecordComponentElement(Element element) { + return RecordComponentElementWrapper.wrap((RecordComponentElement) element); + } + + public static RecordComponentElementWrapper wrap(RecordComponentElement moduleElement) { + return new RecordComponentElementWrapper(moduleElement); + } + + public static List wrapList(List moduleElements) { + return moduleElements.stream().map(RecordComponentElementWrapper::new).collect(Collectors.toList()); + } + +} diff --git a/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java b/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java new file mode 100644 index 00000000..dc2d1fee --- /dev/null +++ b/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java @@ -0,0 +1,165 @@ +package io.toolisticon.aptk.tools.wrapper; + +import io.toolisticon.aptk.common.ToolingProvider; +import io.toolisticon.aptk.tools.corematcher.AptkCoreMatchers; +import io.toolisticon.cute.Cute; +import io.toolisticon.cute.PassIn; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +import javax.lang.model.element.TypeElement; +import java.util.Set; +import java.util.stream.Collectors; + +public class Java16Tests { + + @PassIn + record MyRecord(String name, String surname){} + + @Test + public void test_records_isRecord() { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + + ElementWrapper elementWrapper = ElementWrapper.wrap(element); + + MatcherAssert.assertThat("Should detect record ", elementWrapper.isRecord()); + MatcherAssert.assertThat("Should not detect record ", !TypeElementWrapper.getByClass(Java16Tests.class).get().isRecord()); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + @Test + public void test_records_isTypeElement() { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + + ElementWrapper elementWrapper = ElementWrapper.wrap(element); + + MatcherAssert.assertThat("Should detect record ", elementWrapper.isTypeElement()); + MatcherAssert.assertThat("Should return false", !elementWrapper.isExecutableElement()); + MatcherAssert.assertThat("Should return false ", !elementWrapper.isVariableElement()); + MatcherAssert.assertThat("Should return false ", !elementWrapper.isTypeParameterElement()); + MatcherAssert.assertThat("Should return false", !elementWrapper.isModuleElement()); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + + @Test + public void test_recordComponent_isRecordComponent() { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + + TypeElement typeElement = (TypeElement) element; + + ElementWrapper elementWrapper = ElementWrapper.wrap(typeElement.getRecordComponents().get(0)); + + MatcherAssert.assertThat("Should detect record ", elementWrapper.isRecordComponent()); + MatcherAssert.assertThat("Should not detect record ", !TypeElementWrapper.getByClass(Java16Tests.class).get().isRecordComponent()); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + @Test + public void test_recordComponent_isTypeElement() { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + + TypeElement typeElement = (TypeElement) element; + + ElementWrapper elementWrapper = ElementWrapper.wrap(typeElement.getRecordComponents().get(0)); + + MatcherAssert.assertThat("Should detect RecordComponentElement ", elementWrapper.isRecordComponentElement()); + MatcherAssert.assertThat("Should detect false ", !elementWrapper.isTypeElement()); + MatcherAssert.assertThat("Should return false", !elementWrapper.isExecutableElement()); + MatcherAssert.assertThat("Should return false ", !elementWrapper.isVariableElement()); + MatcherAssert.assertThat("Should return false ", !elementWrapper.isTypeParameterElement()); + MatcherAssert.assertThat("Should return false", !elementWrapper.isModuleElement()); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + + public void test_recordComponent_simpleName() { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + TypeElement typeElement = (TypeElement) element; + + RecordComponentElementWrapper elementWrapper = RecordComponentElementWrapper.wrap(typeElement.getRecordComponents().get(0)); + MatcherAssert.assertThat( elementWrapper.getSimpleName(), Matchers.is("name")); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + @Test + public void test_recordComponent_filtering_byTypeElement() { + Cute.unitTest().when( (processingEnvironment) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + TypeElementWrapper typeElement = TypeElementWrapper.getByClass(Java16Tests.class).get(); + + Set enclosedTypeElements = typeElement.filterFlattenedEnclosedElementTree().applyFilter(AptkCoreMatchers.IS_TYPE_ELEMENT).getResult().stream().map(e -> e.getQualifiedName().toString()).collect(Collectors.toSet()); + + MatcherAssert.assertThat( enclosedTypeElements, Matchers.contains(MyRecord.class.getCanonicalName())); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + @Test + public void test_recordComponent_filtering_byRecord() { + Cute.unitTest().when( (processingEnvironment) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + TypeElementWrapper typeElement = TypeElementWrapper.getByClass(Java16Tests.class).get(); + + Set enclosedTypeElements = typeElement.filterFlattenedEnclosedElementTree().applyFilter(AptkCoreMatchers.IS_RECORD).getResult().stream().map(e -> e.getQualifiedName().toString()).collect(Collectors.toSet()); + + MatcherAssert.assertThat(enclosedTypeElements, Matchers.hasSize(1)); + MatcherAssert.assertThat( enclosedTypeElements, Matchers.contains(MyRecord.class.getCanonicalName())); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + +} diff --git a/extensions/pom.xml b/extensions/pom.xml index ec52b04a..9bafa412 100644 --- a/extensions/pom.xml +++ b/extensions/pom.xml @@ -26,6 +26,18 @@ + + java-16 + + [16,) + + + + java9 + java16 + + + diff --git a/pom.xml b/pom.xml index fb7101ce..5d5f6272 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,7 @@ 0.11.0 - 1.0.0_RC1 + 1.5.0 4.13.2 @@ -689,8 +689,6 @@ - - junit @@ -760,6 +758,18 @@ ${project.version} + + io.toolisticon.aptk + aptk-tools-java9 + ${project.version} + + + + io.toolisticon.aptk + aptk-tools-java16 + ${project.version} + + io.toolisticon.spiap spiap-api diff --git a/tools/pom.xml b/tools/pom.xml index 8f02f7aa..db1d866d 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -100,6 +100,7 @@ + system ${java.home}/../Classes/classes.jar - + --> diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/BeanUtils.java b/tools/src/main/java/io/toolisticon/aptk/tools/BeanUtils.java index dc0cb27f..2229dab3 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/BeanUtils.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/BeanUtils.java @@ -1,6 +1,5 @@ package io.toolisticon.aptk.tools; -import com.sun.source.tree.StatementTree; import io.toolisticon.aptk.tools.command.impl.GetAttributesCommand; import io.toolisticon.aptk.tools.corematcher.AptkCoreMatchers; import io.toolisticon.aptk.tools.fluentfilter.FluentElementFilter; @@ -20,7 +19,6 @@ import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.regex.Pattern; /** * Utility class to handle bean related tasks. @@ -163,6 +161,7 @@ public static boolean isDefaultNoargConstructor(ExecutableElement element) { return false; } + /*- // now check statements of constructor List statements = ProcessingEnvironmentUtils.getTrees().getTree(element).getBody().getStatements(); @@ -171,7 +170,8 @@ public static boolean isDefaultNoargConstructor(ExecutableElement element) { } return Pattern.compile("^\\s*super\\(\\);?\\s*$").matcher(statements.get(0).toString()).matches(); - + */ + return true; } public static boolean isAttribute(VariableElement field) { diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/ElementUtils.java b/tools/src/main/java/io/toolisticon/aptk/tools/ElementUtils.java index 3315e388..8c8c3319 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/ElementUtils.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/ElementUtils.java @@ -42,6 +42,16 @@ public static final class CheckKindOfElement { */ private final static String KIND_MODULE = "MODULE"; + /** + * Needed for handling Record Type until source level is java 16. + */ + private final static String KIND_RECORD = "RECORD"; + + /** + * Needed for handling Record Component Type until source level is java 16. + */ + private final static String KIND_RECORD_COMPONENT = "RECORD_COMPONENT"; + /** * Hidden constructor. */ @@ -60,6 +70,26 @@ public static boolean isEnum(Element e) { return isOfKind(e, ElementKind.ENUM); } + /** + * Checks if passed Element instance is of kind enum. + * + * @param e the element to check + * @return true if passed element is of kind enum, otherwise false + */ + public static boolean isRecord(Element e) { + return (e != null && e.getKind().name().equals(KIND_RECORD)); + } + + /** + * Checks if passed Element instance is of kind enum. + * + * @param e the element to check + * @return true if passed element is of kind enum, otherwise false + */ + public static boolean isRecordComponent(Element e) { + return (e != null && e.getKind().name().equals(KIND_RECORD_COMPONENT)); + } + /** * Checks if passed Element instance is of kind class. * @@ -204,7 +234,8 @@ public static boolean isOfKind(Element e, ElementKind kind) { public static final class CastElement { // look up tables for the different kind of types - private static final Set TYPE_ELEMENT_KIND_LUT = Utilities.convertVarargsToSet(ElementKind.CLASS, ElementKind.INTERFACE, ElementKind.ENUM, ElementKind.ANNOTATION_TYPE); + private static final Set TYPE_ELEMENT_KIND_LUT = Utilities.convertVarargsToSet(ElementKind.CLASS.name(), ElementKind.INTERFACE.name(), ElementKind.ENUM.name(), ElementKind.ANNOTATION_TYPE.name(), "RECORD"); + private static final Set RECORD_COMPONENT_ELEMENT_KIND_LUT = Utilities.convertVarargsToSet( "RECORD_COMPONENT"); private static final Set TYPE_PARAMETER_ELEMENT_KIND_LUT = Utilities.convertVarargsToSet(ElementKind.TYPE_PARAMETER); private static final Set VARIABLE_ELEMENT_KIND_LUT = Utilities.convertVarargsToSet(ElementKind.PARAMETER, ElementKind.FIELD); private static final Set EXECUTABLE_ELEMENT_KIND_LUT = Utilities.convertVarargsToSet(ElementKind.CONSTRUCTOR, ElementKind.METHOD); @@ -227,7 +258,17 @@ private CastElement() { * @return true if passed element can be cast to TypeElement, otherwise false */ public static boolean isTypeElement(Element e) { - return e != null && TYPE_ELEMENT_KIND_LUT.contains(e.getKind()); + return e != null && TYPE_ELEMENT_KIND_LUT.contains(e.getKind().name()); + } + + /** + * Checks if passed element can be cast to RecordComponentElement. + * + * @param e the element to check + * @return true if passed element can be cast to RecordComponentElement, otherwise false + */ + public static boolean isRecordComponentElement(Element e) { + return e != null && RECORD_COMPONENT_ELEMENT_KIND_LUT.contains(e.getKind().name()); } /** diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/ProcessingEnvironmentUtils.java b/tools/src/main/java/io/toolisticon/aptk/tools/ProcessingEnvironmentUtils.java index 1645872e..43799f44 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/ProcessingEnvironmentUtils.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/ProcessingEnvironmentUtils.java @@ -1,6 +1,5 @@ package io.toolisticon.aptk.tools; -import com.sun.source.util.Trees; import io.toolisticon.aptk.common.ToolingProvider; import javax.annotation.processing.Filer; @@ -67,14 +66,4 @@ public static ProcessingEnvironment getProcessingEnvironment() { return ToolingProvider.getTooling().getProcessingEnvironment(); } - /** - * Gets Trees instance. - * - * @return The trees instance - */ - public static Trees getTrees() { - return Trees.instance(ToolingProvider.getTooling().getProcessingEnvironment()); - } - - } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/AptkCoreMatchers.java b/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/AptkCoreMatchers.java index 85c3511c..dc04e290 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/AptkCoreMatchers.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/AptkCoreMatchers.java @@ -42,6 +42,7 @@ import io.toolisticon.aptk.tools.matcher.impl.IsPackageElementMatcher; import io.toolisticon.aptk.tools.matcher.impl.IsPackageMatcher; import io.toolisticon.aptk.tools.matcher.impl.IsParameterMatcher; +import io.toolisticon.aptk.tools.matcher.impl.IsRecordMatcher; import io.toolisticon.aptk.tools.matcher.impl.IsSetterMethodMatcher; import io.toolisticon.aptk.tools.matcher.impl.IsTypeElementMatcher; import io.toolisticon.aptk.tools.matcher.impl.IsTypeEqualFqnMatcher; @@ -252,67 +253,73 @@ protected AptkCoreMatchers() { /** * Matcher to check if passed element is a ExecutableElement. */ - public final static IsCoreMatcher IS_EXECUTABLE_ELEMENT = new IsCoreMatcher<>(new IsExecutableElementMatcher(), CoreMatcherValidationMessages.IS_EXECUTABLE_ELEMENT); + public final static IsCoreMatcher IS_EXECUTABLE_ELEMENT = new IsCoreMatcher<>(new IsExecutableElementMatcher<>(), CoreMatcherValidationMessages.IS_EXECUTABLE_ELEMENT); /** * Matcher to check if passed element is a TypeElement. */ - public final static IsCoreMatcher IS_TYPE_ELEMENT = new IsCoreMatcher<>(new IsTypeElementMatcher(), CoreMatcherValidationMessages.IS_TYPE_ELEMENT); + public final static IsCoreMatcher IS_TYPE_ELEMENT = new IsCoreMatcher<>(new IsTypeElementMatcher<>(), CoreMatcherValidationMessages.IS_TYPE_ELEMENT); /** * Matcher to check if passed element is a VariableElement. */ - public final static IsCoreMatcher IS_VARIABLE_ELEMENT = new IsCoreMatcher<>(new IsVariableElementMatcher(), CoreMatcherValidationMessages.IS_VARIABLE_ELEMENT); + public final static IsCoreMatcher IS_VARIABLE_ELEMENT = new IsCoreMatcher<>(new IsVariableElementMatcher<>(), CoreMatcherValidationMessages.IS_VARIABLE_ELEMENT); /** * Matcher to check if passed element is a PackageElement. */ - public final static IsCoreMatcher IS_PACKAGE_ELEMENT = new IsCoreMatcher<>(new IsPackageElementMatcher(), CoreMatcherValidationMessages.IS_PACKAGE_ELEMENT); + public final static IsCoreMatcher IS_PACKAGE_ELEMENT = new IsCoreMatcher<>(new IsPackageElementMatcher<>(), CoreMatcherValidationMessages.IS_PACKAGE_ELEMENT); /** * Matcher to check if passed element represents a package. */ - public final static IsElementBasedCoreMatcher IS_PACKAGE = new IsElementBasedCoreMatcher<>(new IsPackageMatcher(), CoreMatcherValidationMessages.IS_PACKAGE); + public final static IsElementBasedCoreMatcher IS_PACKAGE = new IsElementBasedCoreMatcher<>(new IsPackageMatcher<>(), CoreMatcherValidationMessages.IS_PACKAGE); /** * Matcher to check if passed element represents a class. */ - public final static IsElementBasedCoreMatcher IS_CLASS = new IsElementBasedCoreMatcher<>(new IsClassMatcher(), CoreMatcherValidationMessages.IS_CLASS); + public final static IsElementBasedCoreMatcher IS_CLASS = new IsElementBasedCoreMatcher<>(new IsClassMatcher<>(), CoreMatcherValidationMessages.IS_CLASS); /** * Matcher to check if passed element represents an enum. */ - public final static IsElementBasedCoreMatcher IS_ENUM = new IsElementBasedCoreMatcher<>(new IsEnumMatcher(), CoreMatcherValidationMessages.IS_ENUM); + public final static IsElementBasedCoreMatcher IS_ENUM = new IsElementBasedCoreMatcher<>(new IsEnumMatcher<>(), CoreMatcherValidationMessages.IS_ENUM); + + /** + * Matcher to check if passed element represents a record. + */ + public final static IsElementBasedCoreMatcher IS_RECORD = new IsElementBasedCoreMatcher<>(new IsRecordMatcher<>(), CoreMatcherValidationMessages.IS_RECORD); + /** * Matcher to check if passed element represents an interface. */ - public final static IsElementBasedCoreMatcher IS_INTERFACE = new IsElementBasedCoreMatcher<>(new IsInterfaceMatcher(), CoreMatcherValidationMessages.IS_INTERFACE); + public final static IsElementBasedCoreMatcher IS_INTERFACE = new IsElementBasedCoreMatcher<>(new IsInterfaceMatcher<>(), CoreMatcherValidationMessages.IS_INTERFACE); /** * Matcher to check if passed element represents a method. */ - public final static IsElementBasedCoreMatcher IS_METHOD = new IsElementBasedCoreMatcher<>(new IsMethodMatcher(), CoreMatcherValidationMessages.IS_METHOD); + public final static IsElementBasedCoreMatcher IS_METHOD = new IsElementBasedCoreMatcher<>(new IsMethodMatcher<>(), CoreMatcherValidationMessages.IS_METHOD); /** * Matcher to check if passed element represents a constructor. */ - public final static IsElementBasedCoreMatcher IS_CONSTRUCTOR = new IsElementBasedCoreMatcher<>(new IsConstructorMatcher(), CoreMatcherValidationMessages.IS_CONSTRUCTOR); + public final static IsElementBasedCoreMatcher IS_CONSTRUCTOR = new IsElementBasedCoreMatcher<>(new IsConstructorMatcher<>(), CoreMatcherValidationMessages.IS_CONSTRUCTOR); /** * Matcher to check if passed element represents an annotation type. */ - public final static IsElementBasedCoreMatcher IS_ANNOTATION_TYPE = new IsElementBasedCoreMatcher<>(new IsAnnotationTypeMatcher(), CoreMatcherValidationMessages.IS_ANNOTATION_TYPE); + public final static IsElementBasedCoreMatcher IS_ANNOTATION_TYPE = new IsElementBasedCoreMatcher<>(new IsAnnotationTypeMatcher<>(), CoreMatcherValidationMessages.IS_ANNOTATION_TYPE); /** * Matcher to check if passed element represents a field. */ - public final static IsElementBasedCoreMatcher IS_FIELD = new IsElementBasedCoreMatcher<>(new IsFieldMatcher(), CoreMatcherValidationMessages.IS_FIELD); + public final static IsElementBasedCoreMatcher IS_FIELD = new IsElementBasedCoreMatcher<>(new IsFieldMatcher<>(), CoreMatcherValidationMessages.IS_FIELD); /** * Matcher to check if passed element represents a parameter. */ - public final static IsElementBasedCoreMatcher IS_PARAMETER = new IsElementBasedCoreMatcher<>(new IsParameterMatcher(), CoreMatcherValidationMessages.IS_PARAMETER); + public final static IsElementBasedCoreMatcher IS_PARAMETER = new IsElementBasedCoreMatcher<>(new IsParameterMatcher<>(), CoreMatcherValidationMessages.IS_PARAMETER); } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/CoreMatcherValidationMessages.java b/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/CoreMatcherValidationMessages.java index aafe2a36..a27b3168 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/CoreMatcherValidationMessages.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/corematcher/CoreMatcherValidationMessages.java @@ -39,6 +39,9 @@ public enum CoreMatcherValidationMessages implements ValidationMessage { IS_CLASS("CM_IS_CLASS", "Element must ${0} represent a Class"), IS_ENUM("CM_IS_ENUM", "Element must ${0} represent an enum"), + + IS_RECORD("CM_IS_ENUM", "Element must ${0} represent a record"), + IS_INTERFACE("CM_IS_INTERFACE", "Element must ${0} represent an interface"), IS_METHOD("CM_IS_METHOD", "Element must ${0} represent a method"), diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/matcher/impl/IsRecordMatcher.java b/tools/src/main/java/io/toolisticon/aptk/tools/matcher/impl/IsRecordMatcher.java new file mode 100644 index 00000000..ec3e479f --- /dev/null +++ b/tools/src/main/java/io/toolisticon/aptk/tools/matcher/impl/IsRecordMatcher.java @@ -0,0 +1,19 @@ +package io.toolisticon.aptk.tools.matcher.impl; + +import io.toolisticon.aptk.tools.ElementUtils; +import io.toolisticon.aptk.tools.matcher.ImplicitMatcher; + +import javax.lang.model.element.Element; + + +/** + * Implicit matcher that checks if a passed element is an enum. + */ +public class IsRecordMatcher implements ImplicitMatcher { + + @Override + public boolean check(ELEMENT element) { + return ElementUtils.CheckKindOfElement.isRecord(element); + } + +} \ No newline at end of file diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java index 7f5075fb..0de9deb0 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java @@ -520,6 +520,24 @@ public boolean isEnum() { return ElementUtils.CheckKindOfElement.isEnum(this.element); } + /** + * Checks if wrapped element represents a record. + * + * @return true if wrapped element represents a record, otherwise false + */ + public boolean isRecord() { + return ElementUtils.CheckKindOfElement.isRecord(this.element); + } + + /** + * Checks if wrapped element represents a record. + * + * @return true if wrapped element represents a record, otherwise false + */ + public boolean isRecordComponent() { + return ElementUtils.CheckKindOfElement.isRecordComponent(this.element); + } + /** * Checks if wrapped element represents an annotation. * @@ -529,6 +547,7 @@ public boolean isAnnotation() { return ElementUtils.CheckKindOfElement.isAnnotation(this.element); } + /** * Checks if wrapped element is a repeatable annotation. * @return if wrapped element represents a repeatable annotation, otherwise false @@ -626,6 +645,14 @@ public boolean isTypeElement() { return ElementUtils.CastElement.isTypeElement(element); } + /** + * Checks if wrapped element is a RecordComponentElement. + * + * @return true if wrapped element is a RecordComponentElement, otherwise false + */ + public boolean isRecordComponentElement() { + return ElementUtils.CastElement.isRecordComponentElement(element); + } /** * Checks if wrapped element is a ExecutableElement. diff --git a/tools/src/test/java/io/toolisticon/aptk/tools/BeanUtilsTest.java b/tools/src/test/java/io/toolisticon/aptk/tools/BeanUtilsTest.java index e5300485..688d80b8 100644 --- a/tools/src/test/java/io/toolisticon/aptk/tools/BeanUtilsTest.java +++ b/tools/src/test/java/io/toolisticon/aptk/tools/BeanUtilsTest.java @@ -1,6 +1,5 @@ package io.toolisticon.aptk.tools; -import com.sun.source.tree.StatementTree; import io.toolisticon.aptk.cute.APTKUnitTestProcessor; import io.toolisticon.aptk.tools.corematcher.AptkCoreMatchers; import io.toolisticon.aptk.tools.fluentfilter.FluentElementFilter; @@ -10,6 +9,7 @@ import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import javax.annotation.processing.ProcessingEnvironment; @@ -18,7 +18,6 @@ import javax.lang.model.element.VariableElement; import java.util.Arrays; import java.util.HashSet; -import java.util.List; import java.util.Set; /** @@ -322,6 +321,7 @@ public void aptkUnitTest(ProcessingEnvironment processingEnvironment, TypeElemen } @Test + @Ignore public void isDefaultNoargConstructor_explicitNoargConstructor() { unitTestBuilder @@ -359,9 +359,6 @@ public void aptkUnitTest(ProcessingEnvironment processingEnvironment, TypeElemen .applyFilter(AptkCoreMatchers.IS_CONSTRUCTOR) .getResult().get(0); - List statements = ProcessingEnvironmentUtils.getTrees().getTree(constructor).getBody().getStatements(); - - MatcherAssert.assertThat("Should return true for explicit constructor that looks like default constructor", BeanUtils.isDefaultNoargConstructor(constructor)); MatcherAssert.assertThat("Should return true for explicit constructor that looks like default constructor", BeanUtils.hasDefaultNoargsConstructor(element)); From 86dfa0a732dc3d1122bdcb2e32c0363abb3c6345 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Tue, 9 Apr 2024 16:15:22 +0200 Subject: [PATCH 03/14] [#148] support records and modules via reflection --- .../RecordComponentElementWrapper.java | 72 ------------------- .../aptk/tools/wrapper/Java16Tests.java | 31 ++++---- .../tools/wrapper/ModuleElementWrapper.java | 47 ------------ .../wrapper/ModuleElementWrapperTest.java | 46 ++++++------ .../aptk/tools/wrapper/ElementWrapper.java | 9 +++ .../tools/wrapper/ModuleElementWrapper.java | 71 ++++++++++++++++++ .../RecordComponentElementWrapper.java | 49 +++++++++++++ .../tools/wrapper/TypeElementWrapper.java | 17 +++++ 8 files changed, 185 insertions(+), 157 deletions(-) delete mode 100644 extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java delete mode 100644 extensions/java9/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java create mode 100644 tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java create mode 100644 tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java diff --git a/extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java b/extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java deleted file mode 100644 index 30cb7233..00000000 --- a/extensions/java16/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java +++ /dev/null @@ -1,72 +0,0 @@ -package io.toolisticon.aptk.tools.wrapper; - -import javax.lang.model.element.Element; -import javax.lang.model.element.RecordComponentElement; -import javax.lang.model.element.TypeElement; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; - -/** - * Wrapper class for RecordComponentElementWrapper. - */ -public class RecordComponentElementWrapper extends ElementWrapper { - private RecordComponentElementWrapper(RecordComponentElement recordComponentElement) { - super(recordComponentElement); - } - - /** - * Gets the enclosing records TypeElement - * @return the wrapped enclosing records TypeElement - */ - public TypeElementWrapper getEnclosingRecordTypeElement() { - return TypeElementWrapper.wrap((TypeElement) element.getEnclosingElement()); - } - - /** - * Wraps the getAccessor method, but returns a ExecutableElementWrapper - * @return the accessors wrapped ExecutableElement - */ - public ExecutableElementWrapper getAccessor() { - return ExecutableElementWrapper.wrap(element.getAccessor()); - } - - /** - * Gets the record components for a TypeElementWrapper. - * @param typeElement the type element wrapper to get the record components for - * @return A list containing the wrapped RecordComponentElement if they exist, otherwise an empty list. - */ - public static List getRecordComponents(TypeElementWrapper typeElement) { - if (typeElement == null) { - return Collections.EMPTY_LIST; - } - return getRecordComponents(typeElement.unwrap()); - } - - /** - * Gets the record components for a TypeElement. - * @param typeElement the type element wrapper to get the record components for - * @return A list containing the wrapped RecordComponentElement if they exist, otherwise an empty list. - */ - public static List getRecordComponents(TypeElement typeElement) { - if (typeElement == null) { - return Collections.EMPTY_LIST; - } - - return typeElement.getRecordComponents().stream().map(RecordComponentElementWrapper::wrap).toList(); - - } - - public static RecordComponentElementWrapper toRecordComponentElement(Element element) { - return RecordComponentElementWrapper.wrap((RecordComponentElement) element); - } - - public static RecordComponentElementWrapper wrap(RecordComponentElement moduleElement) { - return new RecordComponentElementWrapper(moduleElement); - } - - public static List wrapList(List moduleElements) { - return moduleElements.stream().map(RecordComponentElementWrapper::new).collect(Collectors.toList()); - } - -} diff --git a/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java b/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java index dc2d1fee..74574d6a 100644 --- a/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java +++ b/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java @@ -15,11 +15,12 @@ public class Java16Tests { @PassIn - record MyRecord(String name, String surname){} + record MyRecord(String name, String surname) { + } @Test public void test_records_isRecord() { - Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest((processingEnvironment, element) -> { try { ToolingProvider.setTooling(processingEnvironment); @@ -38,7 +39,7 @@ public void test_records_isRecord() { @Test public void test_records_isTypeElement() { - Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest((processingEnvironment, element) -> { try { ToolingProvider.setTooling(processingEnvironment); @@ -61,7 +62,7 @@ public void test_records_isTypeElement() { @Test public void test_recordComponent_isRecordComponent() { - Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest((processingEnvironment, element) -> { try { ToolingProvider.setTooling(processingEnvironment); @@ -82,7 +83,7 @@ public void test_recordComponent_isRecordComponent() { @Test public void test_recordComponent_isTypeElement() { - Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest((processingEnvironment, element) -> { try { ToolingProvider.setTooling(processingEnvironment); @@ -107,13 +108,13 @@ public void test_recordComponent_isTypeElement() { public void test_recordComponent_simpleName() { - Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest( (processingEnvironment, element) -> { + Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest((processingEnvironment, element) -> { try { ToolingProvider.setTooling(processingEnvironment); - TypeElement typeElement = (TypeElement) element; + TypeElementWrapper typeElement = TypeElementWrapper.wrap(element); - RecordComponentElementWrapper elementWrapper = RecordComponentElementWrapper.wrap(typeElement.getRecordComponents().get(0)); - MatcherAssert.assertThat( elementWrapper.getSimpleName(), Matchers.is("name")); + RecordComponentElementWrapper elementWrapper = typeElement.getRecordComponents().get(0); + MatcherAssert.assertThat(elementWrapper.getSimpleName(), Matchers.is("name")); } finally { ToolingProvider.clearTooling(); @@ -125,14 +126,14 @@ public void test_recordComponent_simpleName() { @Test public void test_recordComponent_filtering_byTypeElement() { - Cute.unitTest().when( (processingEnvironment) -> { + Cute.unitTest().when((processingEnvironment) -> { try { ToolingProvider.setTooling(processingEnvironment); TypeElementWrapper typeElement = TypeElementWrapper.getByClass(Java16Tests.class).get(); - Set enclosedTypeElements = typeElement.filterFlattenedEnclosedElementTree().applyFilter(AptkCoreMatchers.IS_TYPE_ELEMENT).getResult().stream().map(e -> e.getQualifiedName().toString()).collect(Collectors.toSet()); + Set enclosedTypeElements = typeElement.filterFlattenedEnclosedElementTree().applyFilter(AptkCoreMatchers.IS_TYPE_ELEMENT).getResult().stream().map(e -> e.getQualifiedName().toString()).collect(Collectors.toSet()); - MatcherAssert.assertThat( enclosedTypeElements, Matchers.contains(MyRecord.class.getCanonicalName())); + MatcherAssert.assertThat(enclosedTypeElements, Matchers.contains(MyRecord.class.getCanonicalName())); } finally { ToolingProvider.clearTooling(); @@ -144,15 +145,15 @@ public void test_recordComponent_filtering_byTypeElement() { @Test public void test_recordComponent_filtering_byRecord() { - Cute.unitTest().when( (processingEnvironment) -> { + Cute.unitTest().when((processingEnvironment) -> { try { ToolingProvider.setTooling(processingEnvironment); TypeElementWrapper typeElement = TypeElementWrapper.getByClass(Java16Tests.class).get(); - Set enclosedTypeElements = typeElement.filterFlattenedEnclosedElementTree().applyFilter(AptkCoreMatchers.IS_RECORD).getResult().stream().map(e -> e.getQualifiedName().toString()).collect(Collectors.toSet()); + Set enclosedTypeElements = typeElement.filterFlattenedEnclosedElementTree().applyFilter(AptkCoreMatchers.IS_RECORD).getResult().stream().map(e -> e.getQualifiedName().toString()).collect(Collectors.toSet()); MatcherAssert.assertThat(enclosedTypeElements, Matchers.hasSize(1)); - MatcherAssert.assertThat( enclosedTypeElements, Matchers.contains(MyRecord.class.getCanonicalName())); + MatcherAssert.assertThat(enclosedTypeElements, Matchers.contains(MyRecord.class.getCanonicalName())); } finally { ToolingProvider.clearTooling(); diff --git a/extensions/java9/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java b/extensions/java9/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java deleted file mode 100644 index aeea5432..00000000 --- a/extensions/java9/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.toolisticon.aptk.tools.wrapper; - -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ModuleElement; -import java.util.List; -import java.util.stream.Collectors; - -public class ModuleElementWrapper extends ElementWrapper { - - private ModuleElementWrapper(ModuleElement moduleElement) { - super(moduleElement); - } - - public String getQualifiedName() { - return this.element.getQualifiedName().toString(); - } - - public boolean hasQualifiedName(String name) { - return name != null && this.getQualifiedName().equals(name); - } - - public boolean isOpen() { - return this.element.isOpen(); - } - - public boolean isUnnamed() { - return this.element.isUnnamed(); - } - - public List getDirectives() { - return this.element.getDirectives(); - } - - public static ModuleElementWrapper toModuleElement(Element element) { - return ModuleElementWrapper.wrap((ModuleElement) element); - } - - public static ModuleElementWrapper wrap(ModuleElement moduleElement) { - return new ModuleElementWrapper(moduleElement); - } - - public static List wrapList(List moduleElements) { - return moduleElements.stream().map(ModuleElementWrapper::new).collect(Collectors.toList()); - } - -} diff --git a/extensions/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java b/extensions/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java index 406c28b2..d2d80d18 100644 --- a/extensions/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java +++ b/extensions/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java @@ -7,6 +7,7 @@ import org.junit.Test; import org.mockito.Mockito; +import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.Name; @@ -18,10 +19,14 @@ public class ModuleElementWrapperTest { + + @Test public void testCreationOfWrapperAndUnwrap() { ModuleElement moduleElement = Mockito.mock(ModuleElement.class); - ModuleElementWrapper unit = ModuleElementWrapper.wrap(moduleElement); + Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); + + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); MatcherAssert.assertThat(unit, Matchers.notNullValue()); MatcherAssert.assertThat(unit.unwrap(), Matchers.is(moduleElement)); } @@ -29,20 +34,24 @@ public void testCreationOfWrapperAndUnwrap() { @Test public void test_getQualifiedName() { ModuleElement moduleElement = Mockito.mock(ModuleElement.class); + Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); + Name name = Mockito.mock(Name.class); Mockito.when(name.toString()).thenReturn("JUPP"); Mockito.when(moduleElement.getQualifiedName()).thenReturn(name); - ModuleElementWrapper unit = ModuleElementWrapper.wrap(moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); MatcherAssert.assertThat(unit.getQualifiedName(), Matchers.is("JUPP")); } @Test public void test_hasQualifiedName() { ModuleElement moduleElement = Mockito.mock(ModuleElement.class); + Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); + Name name = Mockito.mock(Name.class); Mockito.when(name.toString()).thenReturn("YES"); Mockito.when(moduleElement.getQualifiedName()).thenReturn(name); - ModuleElementWrapper unit = ModuleElementWrapper.wrap(moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); MatcherAssert.assertThat(unit.hasQualifiedName("YES"), Matchers.is(true)); MatcherAssert.assertThat(unit.hasQualifiedName("NO"), Matchers.is(false)); MatcherAssert.assertThat(unit.hasQualifiedName(null), Matchers.is(false)); @@ -51,7 +60,9 @@ public void test_hasQualifiedName() { @Test public void proxyTests_isOpen() { ModuleElement moduleElement = Mockito.spy(ModuleElement.class); - ModuleElementWrapper unit = ModuleElementWrapper.wrap(moduleElement); + Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); + + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); unit.isOpen(); Mockito.verify(moduleElement, Mockito.times(1)).isOpen(); @@ -61,28 +72,33 @@ public void proxyTests_isOpen() { @Test public void proxyTests_isUnnamed() { ModuleElement moduleElement = Mockito.spy(ModuleElement.class); - ModuleElementWrapper unit = ModuleElementWrapper.wrap(moduleElement); + Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); + + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); unit.isUnnamed(); Mockito.verify(moduleElement, Mockito.times(1)).isUnnamed(); } + /*- + // TODO: MUST IMPLEMENT DIRECTIVES VIA REFLECTION @Test public void proxyTests_getDirectives() { ModuleElement moduleElement = Mockito.spy(ModuleElement.class); - ModuleElementWrapper unit = ModuleElementWrapper.wrap(moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); unit.getDirectives(); Mockito.verify(moduleElement, Mockito.times(1)).getDirectives(); } + */ @Test public void test_isModuleElement() { ModuleElement moduleElement = Mockito.mock(ModuleElement.class); - Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); + MatcherAssert.assertThat(ElementWrapper.wrap(moduleElement).isModule(), Matchers.is(true)); @@ -91,21 +107,5 @@ public void test_isModuleElement() { MatcherAssert.assertThat(ElementWrapper.wrap(typeElement).isModuleElement(), Matchers.is(false)); } -/*- - - public static boolean isModuleElement(Element element) { - return element != null & element.getKind().equals(ElementKind.MODULE); - } - - public static ModuleElementWrapperTest toModuleElement(Element element) { - return ModuleElementWrapperTest.wrap((ModuleElement) element); - } - - public static ModuleElementWrapperTest wrap(ModuleElement moduleElement) { - return new ModuleElementWrapperTest(moduleElement); - } - - - */ } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java index 0de9deb0..dd6b39ea 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java @@ -16,6 +16,7 @@ import javax.lang.model.element.TypeElement; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -746,4 +747,12 @@ public static ExecutableElementWrapper toExecutableElementWrapper(ElementWrapper return ExecutableElementWrapper.wrap(ElementUtils.CastElement.castToExecutableElement(wrapper.unwrap())); } + protected TARGET_TYPE invokeParameterlessMethodOfElement(String methodName, TARGET_TYPE defaultReturnValue) { + try { + return (TARGET_TYPE) this.element.getClass().getMethod(methodName).invoke(element); + } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { + return defaultReturnValue; + } + } + } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java new file mode 100644 index 00000000..77b01c59 --- /dev/null +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java @@ -0,0 +1,71 @@ +package io.toolisticon.aptk.tools.wrapper; + +import javax.lang.model.element.Element; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +public class ModuleElementWrapper extends ElementWrapper { + + private ModuleElementWrapper(Element moduleElement) { + super(moduleElement); + } + + public String getQualifiedName() { + // default value not needed + return invokeParameterlessMethodOfElement("getQualifiedName", null).toString(); + } + + public boolean hasQualifiedName(String name) { + return name != null && this.getQualifiedName().equals(name); + } + + public boolean isOpen() { + // default value not needed + return this.invokeParameterlessMethodOfElement("isOpen", false); + } + + public boolean isUnnamed() { + // default value not needed + return this.invokeParameterlessMethodOfElement("isUnnamed", false); + } + + /*- + public List getDirectives() { + return this.element.getDirectives(); + } + */ + + /** + * Converts an ElementWrapper to a ModuleElementWrapper id the wrapped element is a ModuleElement + * + * @param element the element to convert + * @return a ModuleElementWrapper wrapping passed ElementWrapper wraps a ModuleElement, otherwise null + */ + public static ModuleElementWrapper toModuleElement(ElementWrapper element) { + return ModuleElementWrapper.wrap(element.unwrap()); + } + + /** + * Wraps the passed element in ModuleElementWrapper if it is a ModuleElement. + * + * @param element the element to wrap + * @return a ModuleElementWrapper wrapping passed element if it is a ModuleElement, otherwise null + */ + public static ModuleElementWrapper wrap(Element element) { + return (element == null || !"MODULE".equals(element.getKind().name())) ? null : new ModuleElementWrapper(element); + } + + /** + * Wraps a List of ModuleElements. + * Unfortunately because of backward compatibility it is not possible to limit lists component type to ModuleElement. + * So this method will try to wrap all Elements of the passed list. It will drop those not being ModuleElements. + * + * @param moduleElements A List of ModuleElements. + * @return A list of ModuleElementWrapper of elements representing modules that could successfully wrapped, or an empty list. + */ + public static List wrapList(List moduleElements) { + return moduleElements.stream().map(ModuleElementWrapper::new).filter(Objects::nonNull).collect(Collectors.toList()); + } + +} diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java new file mode 100644 index 00000000..a08bd743 --- /dev/null +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java @@ -0,0 +1,49 @@ +package io.toolisticon.aptk.tools.wrapper; + +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.TypeElement; + +/** + * Wrapper class for RecordComponentElementWrapper. + */ +public class RecordComponentElementWrapper extends ElementWrapper { + private RecordComponentElementWrapper(Element recordComponentElement) { + super(recordComponentElement); + } + + /** + * Gets the enclosing records TypeElement + * + * @return the wrapped enclosing records TypeElement + */ + public TypeElementWrapper getEnclosingRecordTypeElement() { + return TypeElementWrapper.wrap((TypeElement) element.getEnclosingElement()); + } + + /** + * Wraps the getAccessor method, but returns a ExecutableElementWrapper + * + * @return the accessors wrapped ExecutableElement + */ + public ExecutableElementWrapper getAccessor() { + // doesn't use default value + return ExecutableElementWrapper.wrap(this.invokeParameterlessMethodOfElement("getAccessor", null)); + } + + public static RecordComponentElementWrapper toRecordComponentElement(ElementWrapper element) { + if (element == null) { + return null; + } + return RecordComponentElementWrapper.wrap(element.unwrap()); + } + + public static RecordComponentElementWrapper wrap(Element element) { + if (element == null || !"RECORD_COMPONENT".equals(element.getKind().name())) { + return null; + } + return new RecordComponentElementWrapper(element); + } + + +} diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java index 830676e0..498ce141 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java @@ -5,6 +5,7 @@ import io.toolisticon.aptk.tools.corematcher.AptkCoreMatchers; import io.toolisticon.aptk.tools.fluentfilter.FluentElementFilter; +import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; @@ -12,6 +13,7 @@ import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; +import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Optional; @@ -261,6 +263,21 @@ public List getEnumValues() { : null; } + /** + * Returns the record components of this class or interface element in declaration order. + * @return the record components, or an empty list if there are none + */ + public List getRecordComponents() { + + if (!isRecord()) { + return Collections.EMPTY_LIST; + } + List recordComponentElements = this.invokeParameterlessMethodOfElement("getRecordComponents", Collections.EMPTY_LIST); + + return recordComponentElements.stream().map(RecordComponentElementWrapper::wrap).collect(Collectors.toList()); + + } + /** * Wraps a TypeElement. * From eeccbc4a4feb3218f250f728a4c1211dea306a54 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Tue, 9 Apr 2024 16:40:33 +0200 Subject: [PATCH 04/14] [#148] changed extension folder to integration test --- {extensions => integrationtest}/java16/pom.xml | 17 +++++++++-------- .../aptk/tools/wrapper/Java16Tests.java | 0 {extensions => integrationtest}/java9/pom.xml | 9 ++++++++- .../aptk/wrapper/ModuleElementWrapperTest.java | 0 {extensions => integrationtest}/pom.xml | 4 ++-- pom.xml | 2 +- .../wrapper/RecordComponentElementWrapper.java | 11 +++++++++++ 7 files changed, 31 insertions(+), 12 deletions(-) rename {extensions => integrationtest}/java16/pom.xml (88%) rename {extensions => integrationtest}/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java (100%) rename {extensions => integrationtest}/java9/pom.xml (89%) rename {extensions => integrationtest}/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java (100%) rename {extensions => integrationtest}/pom.xml (91%) diff --git a/extensions/java16/pom.xml b/integrationtest/java16/pom.xml similarity index 88% rename from extensions/java16/pom.xml rename to integrationtest/java16/pom.xml index 814be0bb..0e86bce7 100644 --- a/extensions/java16/pom.xml +++ b/integrationtest/java16/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk - extension-parent + integrationtest-parent 0.24.1-148_records-SNAPSHOT @@ -16,12 +16,6 @@ - - - io.toolisticon.aptk - aptk-tools-java9 - - io.toolisticon.aptk aptk-tools @@ -57,7 +51,6 @@ io.toolisticon.aptk:aptk-tools:* - io.toolisticon.aptk:aptk-tools-java9:* *:*:*:*:test:* *:*:*:*:provided:* @@ -84,6 +77,14 @@ + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + diff --git a/extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java b/integrationtest/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java similarity index 100% rename from extensions/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java rename to integrationtest/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java diff --git a/extensions/java9/pom.xml b/integrationtest/java9/pom.xml similarity index 89% rename from extensions/java9/pom.xml rename to integrationtest/java9/pom.xml index 17b2be14..761d794e 100644 --- a/extensions/java9/pom.xml +++ b/integrationtest/java9/pom.xml @@ -7,7 +7,7 @@ io.toolisticon.aptk - extension-parent + integrationtest-parent 0.24.1-148_records-SNAPSHOT @@ -77,6 +77,13 @@ + + org.apache.maven.plugins + maven-deploy-plugin + + true + + diff --git a/extensions/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java b/integrationtest/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java similarity index 100% rename from extensions/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java rename to integrationtest/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java diff --git a/extensions/pom.xml b/integrationtest/pom.xml similarity index 91% rename from extensions/pom.xml rename to integrationtest/pom.xml index 9bafa412..2a587340 100644 --- a/extensions/pom.xml +++ b/integrationtest/pom.xml @@ -1,7 +1,7 @@ 4.0.0 - extension-parent + integrationtest-parent pom @@ -10,7 +10,7 @@ 0.24.1-148_records-SNAPSHOT - extension-parent + integrationtest-parent diff --git a/pom.xml b/pom.xml index 5d5f6272..01f9b5d0 100644 --- a/pom.xml +++ b/pom.xml @@ -18,7 +18,7 @@ tools example templating - extensions + integrationtest annotationwrapper diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java index a08bd743..c41db307 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java @@ -31,6 +31,11 @@ public ExecutableElementWrapper getAccessor() { return ExecutableElementWrapper.wrap(this.invokeParameterlessMethodOfElement("getAccessor", null)); } + /** + * Re-wraps an ElementWrapper to a RecordComponentElementWrapper. + * @param element the wrapper to re-wrap + * @return The RecordComponentElementWrapper or null if the passed ElementWrapper doesn't wrap a RecordComponentElement + */ public static RecordComponentElementWrapper toRecordComponentElement(ElementWrapper element) { if (element == null) { return null; @@ -38,6 +43,12 @@ public static RecordComponentElementWrapper toRecordComponentElement(ElementWrap return RecordComponentElementWrapper.wrap(element.unwrap()); } + /** + * Wraps an element with the RecordComponentElementWrapper. + * + * @param element the element to wrap + * @return the wrapped element, or null if passed element isn't an RecordComponentElement + */ public static RecordComponentElementWrapper wrap(Element element) { if (element == null || !"RECORD_COMPONENT".equals(element.getKind().name())) { return null; From 17fe74f5452e3ef069ebd59ca06a12fb0b9ad814 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Tue, 9 Apr 2024 18:13:36 +0200 Subject: [PATCH 05/14] [#148] added module directives access - still need to add tests --- .../aptk/tools/wrapper/ElementWrapper.java | 6 +- .../tools/wrapper/ModuleElementWrapper.java | 248 +++++++++++++++++- .../tools/wrapper/TypeElementWrapper.java | 10 + 3 files changed, 259 insertions(+), 5 deletions(-) diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java index dd6b39ea..bdb4465a 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java @@ -748,8 +748,12 @@ public static ExecutableElementWrapper toExecutableElementWrapper(ElementWrapper } protected TARGET_TYPE invokeParameterlessMethodOfElement(String methodName, TARGET_TYPE defaultReturnValue) { + return ElementWrapper.invokeParameterlessMethodOfElement(element, methodName, defaultReturnValue); + } + + protected static TARGET_TYPE invokeParameterlessMethodOfElement(Object instance, String methodName, TARGET_TYPE defaultReturnValue) { try { - return (TARGET_TYPE) this.element.getClass().getMethod(methodName).invoke(element); + return (TARGET_TYPE) instance.getClass().getMethod(methodName).invoke(instance); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { return defaultReturnValue; } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java index 77b01c59..3e15108f 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java @@ -1,12 +1,252 @@ package io.toolisticon.aptk.tools.wrapper; import javax.lang.model.element.Element; +import javax.lang.model.element.PackageElement; +import javax.lang.model.element.TypeElement; +import java.lang.annotation.Target; +import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; public class ModuleElementWrapper extends ElementWrapper { + public abstract static class Directive { + + protected final Object wrappedDirective; + + private Directive(Object wrappedDirective) { + this.wrappedDirective = wrappedDirective; + } + + public boolean isExportDirective() { + return isExportDirective(wrappedDirective); + } + + private static boolean isExportDirective(Object instance) { + return "EXPORTS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + } + + public ExportsDirective toExportsDirective() { + return isExportDirective() ? (ExportsDirective) this : null; + } + + + public boolean isOpensDirective() { + return isOpensDirective(wrappedDirective); + } + + private static boolean isOpensDirective(Object instance) { + return "OPENS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + } + + public OpensDirective toOpensDirective() { + return isOpensDirective() ? (OpensDirective) this : null; + } + + public boolean isProvidesDirective() { + return isProvidesDirective(wrappedDirective); + } + + private static boolean isProvidesDirective(Object instance) { + return "PROVIDES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + } + + public ProvidesDirective toProvidesDirective() { + return isProvidesDirective() ? (ProvidesDirective) this : null; + } + + public boolean isRequiresDirective() { + return isRequiresDirective(wrappedDirective); + } + + private static boolean isRequiresDirective(Object instance) { + return "REQUIRES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + } + + public RequiresDirective toRequiresDirective() { + return isRequiresDirective() ? (RequiresDirective) this : null; + } + + public boolean isUsesDirective() { + return isUsesDirective(wrappedDirective); + } + + private static boolean isUsesDirective(Object instance) { + return "USES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + } + + public UsesDirective toUsesDirective() { + return isRequiresDirective() ? (UsesDirective) this : null; + } + + + } + + + public static class ExportsDirective extends Directive { + + + private ExportsDirective(Object wrappedDirective) { + super(wrappedDirective); + } + + /** + * Returns the package being exported. + * + * @return the package being exported + */ + public PackageElementWrapper getPackage() { + return PackageElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getPackage", null)); + } + + /** + * Returns the specific modules to which the package is being exported, or null, if the package is exported to all modules which have readability to this module. + * + * @return the specific modules to which the package is being exported + */ + public List getTargetModules() { + return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, "getTargetModules", Collections.EMPTY_LIST)); + } + + + } + + public static class OpensDirective extends Directive { + + + private OpensDirective(Object wrappedDirective) { + super(wrappedDirective); + } + + /** + * Returns the package being exported. + * + * @return the package being exported + */ + public PackageElementWrapper getPackage() { + return PackageElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getPackage", null)); + } + + /** + * Returns the specific modules to which the package is being exported, or null, if the package is exported to all modules which have readability to this module. + * + * @return the specific modules to which the package is being exported + */ + public List getTargetModules() { + return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, "getTargetModules", Collections.EMPTY_LIST)); + } + + } + + public static class ProvidesDirective extends Directive { + + + private ProvidesDirective(Object wrappedDirective) { + super(wrappedDirective); + } + + /** + * Returns the service being provided + * + * @return the service being provided + */ + public TypeElementWrapper getService(){ + return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getService", null)); + } + + /** + * Returns the implementations of the service being provided. + * + * @return the implementations of the service being provided + */ + public List getImplementations() { + List implementations = (ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, "getTargetModules", Collections.EMPTY_LIST)); + return implementations.stream().map(TypeElementWrapper::wrap).collect(Collectors.toList()); + } + + } + + public static class RequiresDirective extends Directive { + + + private RequiresDirective(Object wrappedDirective) { + super(wrappedDirective); + } + + /** + * Returns the module that is required + * + * @return the module that is required + */ + public ModuleElementWrapper getDependency(){ + return ModuleElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getDependency", null)); + } + + + /** + * Returns whether or not this is a static dependency. + * @return whether or not this is a static dependency. + */ + public boolean isStatic() { + return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective,"isStatic",false); + } + + /** + * Returns whether or not this is a transitive dependency. + * @return whether or not this is a transitive dependency. + */ + boolean isTransitive() { + return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective,"isTransitive",false); + } + + } + + public static class UsesDirective extends Directive { + + private UsesDirective(Object wrappedDirective) { + super(wrappedDirective); + } + + /** + * Returns the service being used + * + * @return the service being used + */ + public TypeElementWrapper getService(){ + return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getService", null)); + } + + + + } + + private static Directive createDirective(Object instance) { + if (instance == null) { + return null; + } + + if (Directive.isExportDirective(instance)) { + return new ExportsDirective(instance); + } else if (Directive.isOpensDirective(instance)) { + return new OpensDirective(instance); + } else if (Directive.isProvidesDirective(instance)) { + return new ProvidesDirective(instance); + } else if (Directive.isRequiresDirective(instance)) { + return new RequiresDirective(instance); + } else if (Directive.isUsesDirective(instance)) { + return new UsesDirective(instance); + } + + return null; + } + + private static List createDirectives (List directives) { + + return directives.stream().map(e -> createDirective(e)).filter(Objects::nonNull).collect(Collectors.toList()); + + } + private ModuleElementWrapper(Element moduleElement) { super(moduleElement); } @@ -30,11 +270,11 @@ public boolean isUnnamed() { return this.invokeParameterlessMethodOfElement("isUnnamed", false); } - /*- - public List getDirectives() { - return this.element.getDirectives(); + + public List getDirectives() { + return createDirectives(this.>invokeParameterlessMethodOfElement("getDirectives", Collections.EMPTY_LIST)); } - */ + /** * Converts an ElementWrapper to a ModuleElementWrapper id the wrapped element is a ModuleElement diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java index 498ce141..9db9529f 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java @@ -278,6 +278,16 @@ public List getRecordComponents() { } + /** + * Returns the permitted classes of this class or interface element in declaration order. + * @return the permitted classes, or an empty list if there are none + */ + public List getPermittedSubclasses() { + List typeMirrors = this.>invokeParameterlessMethodOfElement("getPermittedSubclasses", Collections.EMPTY_LIST); + return typeMirrors.stream().map(TypeMirrorWrapper::wrap).collect(Collectors.toList()); + } + + /** * Wraps a TypeElement. * From c1a15721165876d87aceeb438a206f2d8808f9f6 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 01:27:39 +0200 Subject: [PATCH 06/14] [#148] Added tests for ModuleElementWrapper --- .../wrapper/ModuleElementWrapperTest.java | 82 ++++++- .../testcases/namedModule/MyProcessor.java | 15 ++ .../testcases/namedModule/TestClass.java | 8 + .../testcases/namedModule/module-info.java | 12 + pom.xml | 2 +- .../aptk/tools/wrapper/ElementWrapper.java | 40 +++- .../tools/wrapper/ModuleElementWrapper.java | 224 ++++++++++++------ .../RecordComponentElementWrapper.java | 7 +- .../tools/wrapper/TypeElementWrapper.java | 6 +- .../wrapper/ModulesElementWrapperTest.java | 60 +++++ 10 files changed, 358 insertions(+), 98 deletions(-) create mode 100644 integrationtest/java9/src/test/resources/testcases/namedModule/MyProcessor.java create mode 100644 integrationtest/java9/src/test/resources/testcases/namedModule/TestClass.java create mode 100644 integrationtest/java9/src/test/resources/testcases/namedModule/module-info.java create mode 100644 tools/src/test/java/io/toolisticon/aptk/tools/wrapper/ModulesElementWrapperTest.java diff --git a/integrationtest/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java b/integrationtest/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java index d2d80d18..595362ab 100644 --- a/integrationtest/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java +++ b/integrationtest/java9/src/test/java/io/toolisticon/aptk/wrapper/ModuleElementWrapperTest.java @@ -1,17 +1,22 @@ package io.toolisticon.aptk.wrapper; +import io.toolisticon.aptk.common.ToolingProvider; import io.toolisticon.aptk.tools.wrapper.ElementWrapper; import io.toolisticon.aptk.tools.wrapper.ModuleElementWrapper; +import io.toolisticon.aptk.tools.wrapper.TypeElementWrapper; +import io.toolisticon.cute.Cute; import org.hamcrest.MatcherAssert; import org.hamcrest.Matchers; import org.junit.Test; import org.mockito.Mockito; +import javax.annotation.processing.Processor; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ModuleElement; import javax.lang.model.element.Name; import javax.lang.model.element.TypeElement; +import java.util.Optional; /** * Unit test for {@link io.toolisticon.aptk.tools.wrapper.ModuleElementWrapper}. @@ -19,14 +24,12 @@ public class ModuleElementWrapperTest { - - @Test public void testCreationOfWrapperAndUnwrap() { ModuleElement moduleElement = Mockito.mock(ModuleElement.class); Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); - ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element) moduleElement); MatcherAssert.assertThat(unit, Matchers.notNullValue()); MatcherAssert.assertThat(unit.unwrap(), Matchers.is(moduleElement)); } @@ -39,7 +42,7 @@ public void test_getQualifiedName() { Name name = Mockito.mock(Name.class); Mockito.when(name.toString()).thenReturn("JUPP"); Mockito.when(moduleElement.getQualifiedName()).thenReturn(name); - ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element) moduleElement); MatcherAssert.assertThat(unit.getQualifiedName(), Matchers.is("JUPP")); } @@ -51,7 +54,7 @@ public void test_hasQualifiedName() { Name name = Mockito.mock(Name.class); Mockito.when(name.toString()).thenReturn("YES"); Mockito.when(moduleElement.getQualifiedName()).thenReturn(name); - ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element) moduleElement); MatcherAssert.assertThat(unit.hasQualifiedName("YES"), Matchers.is(true)); MatcherAssert.assertThat(unit.hasQualifiedName("NO"), Matchers.is(false)); MatcherAssert.assertThat(unit.hasQualifiedName(null), Matchers.is(false)); @@ -62,7 +65,7 @@ public void proxyTests_isOpen() { ModuleElement moduleElement = Mockito.spy(ModuleElement.class); Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); - ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element) moduleElement); unit.isOpen(); Mockito.verify(moduleElement, Mockito.times(1)).isOpen(); @@ -74,7 +77,7 @@ public void proxyTests_isUnnamed() { ModuleElement moduleElement = Mockito.spy(ModuleElement.class); Mockito.when(moduleElement.getKind()).thenReturn(ElementKind.MODULE); - ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element)moduleElement); + ModuleElementWrapper unit = ModuleElementWrapper.wrap((Element) moduleElement); unit.isUnnamed(); Mockito.verify(moduleElement, Mockito.times(1)).isUnnamed(); @@ -108,4 +111,69 @@ public void test_isModuleElement() { } + + @Test + public void test_blackbox_ModuleElementWrapper_variousTests() { + Cute.unitTest().given().useSourceFiles("/testcases/namedModule/module-info.java", "/testcases/namedModule/TestClass.java", "/testcases/namedModule/MyProcessor.java") + .when().unitTestWithoutPassIn(processingEnvironment -> { + try { + ToolingProvider.setTooling(processingEnvironment); + TypeElementWrapper typeElementWrapper = TypeElementWrapper.getByFqn("io.toolisticon.aptk.example.regularmodule.TestClass").get(); + Optional moduleElementWrapper = typeElementWrapper.getModule(); + MatcherAssert.assertThat("Should find module", moduleElementWrapper.isPresent()); + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().isModuleElement()); + + MatcherAssert.assertThat(moduleElementWrapper.get().getQualifiedName(), Matchers.is("io.toolisticon.aptk.example")); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives(), Matchers.hasSize(7)); + + // default: requires java.base + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().getDirectives().get(0).isRequiresDirective()); + MatcherAssert.assertThat("Should be false for non static", !moduleElementWrapper.get().getDirectives().get(0).toRequiresDirective().isStatic()); + MatcherAssert.assertThat("Should be false for non transitive", !moduleElementWrapper.get().getDirectives().get(0).toRequiresDirective().isTransitive()); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(0).toRequiresDirective().getDependency().getQualifiedName(), Matchers.is("java.base")); + + // exports io.toolisticon.aptk.example.regularmodule; + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().getDirectives().get(1).isExportDirective()); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(1).toExportsDirective().getPackage().getQualifiedName(), Matchers.is("io.toolisticon.aptk.example.regularmodule")); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(1).toExportsDirective().getTargetModules(), Matchers.hasSize(1)); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(1).toExportsDirective().getTargetModules().get(0).getQualifiedName(), Matchers.is("cute")); + + // requires cute + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().getDirectives().get(2).isRequiresDirective()); + MatcherAssert.assertThat("Should be false for non static", !moduleElementWrapper.get().getDirectives().get(2).toRequiresDirective().isStatic()); + MatcherAssert.assertThat("Should be true for non transitive", moduleElementWrapper.get().getDirectives().get(2).toRequiresDirective().isTransitive()); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(2).toRequiresDirective().getDependency().getQualifiedName(), Matchers.is("cute")); + + // requires jdk.compiler; + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().getDirectives().get(3).isRequiresDirective()); + MatcherAssert.assertThat("Should be true for non static", moduleElementWrapper.get().getDirectives().get(3).toRequiresDirective().isStatic()); + MatcherAssert.assertThat("Should be false for non transitive", !moduleElementWrapper.get().getDirectives().get(3).toRequiresDirective().isTransitive()); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(3).toRequiresDirective().getDependency().getQualifiedName(), Matchers.is("jdk.compiler")); + + // uses Processor + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().getDirectives().get(4).isUsesDirective()); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(4).toUsesDirective().getService().getQualifiedName(), Matchers.is(Processor.class.getCanonicalName())); + + // opens io.toolisticon.aptk.example.regularmodule to cute + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().getDirectives().get(5).isOpensDirective()); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(5).toOpensDirective().getPackage().getQualifiedName(), Matchers.is("io.toolisticon.aptk.example.regularmodule")); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(5).toOpensDirective().getTargetModules().get(0).getQualifiedName(), Matchers.is("cute")); + + // provides Processor with io.toolisticon.aptk.example.regularmodule.MyProcessor; + MatcherAssert.assertThat("Should be true", moduleElementWrapper.get().getDirectives().get(6).isProvidesDirective()); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(6).toProvidesDirective().getService().getQualifiedName(), Matchers.is(Processor.class.getCanonicalName())); + MatcherAssert.assertThat(moduleElementWrapper.get().getDirectives().get(6).toProvidesDirective().getImplementations().get(0).getQualifiedName(), Matchers.is("io.toolisticon.aptk.example.regularmodule.MyProcessor")); + + + } finally { + ToolingProvider.clearTooling(); + } + }) + .thenExpectThat() + .compilationSucceeds() + .executeTest(); + + } + + } diff --git a/integrationtest/java9/src/test/resources/testcases/namedModule/MyProcessor.java b/integrationtest/java9/src/test/resources/testcases/namedModule/MyProcessor.java new file mode 100644 index 00000000..137d7f5c --- /dev/null +++ b/integrationtest/java9/src/test/resources/testcases/namedModule/MyProcessor.java @@ -0,0 +1,15 @@ +package io.toolisticon.aptk.example.regularmodule; + +import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.RoundEnvironment; +import javax.lang.model.element.TypeElement; +import java.util.Set; + +public class MyProcessor extends AbstractProcessor { + + + @Override + public boolean process(Set annotations, RoundEnvironment roundEnv) { + return false; + } +} \ No newline at end of file diff --git a/integrationtest/java9/src/test/resources/testcases/namedModule/TestClass.java b/integrationtest/java9/src/test/resources/testcases/namedModule/TestClass.java new file mode 100644 index 00000000..462a35ac --- /dev/null +++ b/integrationtest/java9/src/test/resources/testcases/namedModule/TestClass.java @@ -0,0 +1,8 @@ +package io.toolisticon.aptk.example.regularmodule; + +import io.toolisticon.cute.PassIn; + +@PassIn +public class TestClass{ + +} \ No newline at end of file diff --git a/integrationtest/java9/src/test/resources/testcases/namedModule/module-info.java b/integrationtest/java9/src/test/resources/testcases/namedModule/module-info.java new file mode 100644 index 00000000..35ebfde5 --- /dev/null +++ b/integrationtest/java9/src/test/resources/testcases/namedModule/module-info.java @@ -0,0 +1,12 @@ +import javax.annotation.processing.Processor; + +module io.toolisticon.aptk.example { + + exports io.toolisticon.aptk.example.regularmodule to cute; + requires transitive cute; + requires static jdk.compiler; + uses Processor; + opens io.toolisticon.aptk.example.regularmodule to cute; + provides Processor with io.toolisticon.aptk.example.regularmodule.MyProcessor; + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 01f9b5d0..50e61fd0 100644 --- a/pom.xml +++ b/pom.xml @@ -87,7 +87,7 @@ 0.11.0 - 1.5.0 + 1.7.0 4.13.2 diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java index bdb4465a..cb0523d5 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java @@ -94,6 +94,18 @@ public boolean hasSimplePackageName(String name) { return name != null && this.getSimplePackageName().equals(name); } + /** + * Gets the module of the wrapped element + * @return an optional containing the wrapped module element + */ + public Optional getModule() { + try { + Element element = ElementUtils.AccessEnclosingElements.getFirstEnclosingElementOfKind(this.element, ElementKind.valueOf("MODULE")); + return element != null ? Optional.of(ModuleElementWrapper.wrap(element)) : Optional.empty(); + } catch (IllegalArgumentException e) { + return Optional.empty(); + } + } /** * Gets the simple name of the element. @@ -176,6 +188,7 @@ public FluentElementFilter filterFlattenedEnclosedElementTree(boolean i /** * Gets all wrapped annotations of element. + * * @return a list containing all annotations of the element */ public List getAnnotations() { @@ -348,6 +361,7 @@ public Optional getAnnotationMirror(String annotationTy /** * Checks if passed annotation is present. + * * @param annotation the annotation tom check * @return true if passed annotation is present, otherwise false */ @@ -357,6 +371,7 @@ public boolean hasAnnotation(Class annotation) { /** * Checks if passed annotation is present. + * * @param annotationFqn the annotation tom check * @return true if passed annotation is present, otherwise false */ @@ -376,7 +391,7 @@ public Optional getAnnotation(Class annotationType) return Optional.ofNullable(element.getAnnotation(annotationType)); } - public Optional> getRepeatableAnnotation (Class annotationType) { + public Optional> getRepeatableAnnotation(Class annotationType) { List result = new ArrayList<>(); @@ -551,19 +566,21 @@ public boolean isAnnotation() { /** * Checks if wrapped element is a repeatable annotation. + * * @return if wrapped element represents a repeatable annotation, otherwise false */ - public boolean isRepeatableAnnotation(){ + public boolean isRepeatableAnnotation() { return isAnnotation() && hasAnnotation(Repeatable.class); } /** * Gets an Optional containing the wrapped repeatable TypeMirror, if the wrapped represents a repeatable annotation. + * * @return The wrapped repeatable annotation Type Mirror or an empty Optional if it doesn't exist */ - public Optional getRepeatableWrapperType(){ + public Optional getRepeatableWrapperType() { - if(isRepeatableAnnotation()){ + if (isRepeatableAnnotation()) { return Optional.of(getAnnotationMirror(Repeatable.class).get().getAttribute().get().getClassValue()); } @@ -747,16 +764,19 @@ public static ExecutableElementWrapper toExecutableElementWrapper(ElementWrapper return ExecutableElementWrapper.wrap(ElementUtils.CastElement.castToExecutableElement(wrapper.unwrap())); } - protected TARGET_TYPE invokeParameterlessMethodOfElement(String methodName, TARGET_TYPE defaultReturnValue) { - return ElementWrapper.invokeParameterlessMethodOfElement(element, methodName, defaultReturnValue); + protected Optional invokeParameterlessMethodOfElement(String interfaceName, String methodName) { + return ElementWrapper.invokeParameterlessMethodOfElement(element, interfaceName, methodName); } - protected static TARGET_TYPE invokeParameterlessMethodOfElement(Object instance, String methodName, TARGET_TYPE defaultReturnValue) { + protected static Optional invokeParameterlessMethodOfElement(Object instance, String interfaceName, String methodName) { try { - return (TARGET_TYPE) instance.getClass().getMethod(methodName).invoke(instance); - } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { - return defaultReturnValue; + Class interfaceClass = Class.forName(interfaceName); + + return Optional.ofNullable((TARGET_TYPE) interfaceClass.getMethod(methodName).invoke(instance)); + } catch (Exception e) { + return Optional.empty(); } } + } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java index 3e15108f..7e3e2749 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java @@ -1,16 +1,31 @@ package io.toolisticon.aptk.tools.wrapper; import javax.lang.model.element.Element; +import javax.lang.model.element.Name; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; -import java.lang.annotation.Target; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; public class ModuleElementWrapper extends ElementWrapper { + private final static String MODULE_ELEMENT_CLASS_NAME = "javax.lang.model.element.ModuleElement"; + private final static String DIRECTIVE_CLASS_NAME = MODULE_ELEMENT_CLASS_NAME + "$Directive"; + private final static String EXPORTS_DIRECTIVE_CLASS_NAME = MODULE_ELEMENT_CLASS_NAME + "$ExportsDirective"; + + private final static String PROVIDES_DIRECTIVE_CLASS_NAME = MODULE_ELEMENT_CLASS_NAME + "$ProvidesDirective"; + + private final static String USES_DIRECTIVE_CLASS_NAME = MODULE_ELEMENT_CLASS_NAME + "$UsesDirective"; + + + private final static String OPENS_DIRECTIVE_CLASS_NAME = MODULE_ELEMENT_CLASS_NAME + "$OpensDirective"; + + private final static String REQUIRES_DIRECTIVE_CLASS_NAME = MODULE_ELEMENT_CLASS_NAME + "$RequiresDirective"; + + public abstract static class Directive { protected final Object wrappedDirective; @@ -24,11 +39,11 @@ public boolean isExportDirective() { } private static boolean isExportDirective(Object instance) { - return "EXPORTS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + return "EXPORTS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); } public ExportsDirective toExportsDirective() { - return isExportDirective() ? (ExportsDirective) this : null; + return (ExportsDirective) this; } @@ -37,11 +52,11 @@ public boolean isOpensDirective() { } private static boolean isOpensDirective(Object instance) { - return "OPENS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + return "OPENS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); } public OpensDirective toOpensDirective() { - return isOpensDirective() ? (OpensDirective) this : null; + return (OpensDirective) this; } public boolean isProvidesDirective() { @@ -49,23 +64,23 @@ public boolean isProvidesDirective() { } private static boolean isProvidesDirective(Object instance) { - return "PROVIDES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + return "PROVIDES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); } public ProvidesDirective toProvidesDirective() { - return isProvidesDirective() ? (ProvidesDirective) this : null; + return (ProvidesDirective) this; } public boolean isRequiresDirective() { return isRequiresDirective(wrappedDirective); } - private static boolean isRequiresDirective(Object instance) { - return "REQUIRES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + private static boolean isRequiresDirective(Object instance) { + return "REQUIRES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); } public RequiresDirective toRequiresDirective() { - return isRequiresDirective() ? (RequiresDirective) this : null; + return (RequiresDirective) this; } public boolean isUsesDirective() { @@ -73,150 +88,206 @@ public boolean isUsesDirective() { } private static boolean isUsesDirective(Object instance) { - return "USES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, "getKind", null).toString()); + return "USES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); } + public UsesDirective toUsesDirective() { - return isRequiresDirective() ? (UsesDirective) this : null; + return (UsesDirective) this; } } - public static class ExportsDirective extends Directive { - - - private ExportsDirective(Object wrappedDirective) { - super(wrappedDirective); - } + public interface ExportsDirective { /** * Returns the package being exported. * * @return the package being exported */ - public PackageElementWrapper getPackage() { - return PackageElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getPackage", null)); - } + PackageElementWrapper getPackage(); /** * Returns the specific modules to which the package is being exported, or null, if the package is exported to all modules which have readability to this module. * * @return the specific modules to which the package is being exported */ - public List getTargetModules() { - return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, "getTargetModules", Collections.EMPTY_LIST)); - } - + List getTargetModules(); } - public static class OpensDirective extends Directive { + static class ExportsDirectiveImpl extends Directive implements ExportsDirective { - private OpensDirective(Object wrappedDirective) { + private ExportsDirectiveImpl(Object wrappedDirective) { super(wrappedDirective); } + @Override + public PackageElementWrapper getPackage() { + Optional result = ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, EXPORTS_DIRECTIVE_CLASS_NAME, "getPackage"); + return PackageElementWrapper.wrap(result.get()); + } + + @Override + public List getTargetModules() { + return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, EXPORTS_DIRECTIVE_CLASS_NAME, "getTargetModules").get()); + } + + + } + + public interface OpensDirective { + + /** - * Returns the package being exported. + * Returns the package being opened. * - * @return the package being exported + * @return the package being opened */ - public PackageElementWrapper getPackage() { - return PackageElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getPackage", null)); - } + PackageElementWrapper getPackage(); /** - * Returns the specific modules to which the package is being exported, or null, if the package is exported to all modules which have readability to this module. + * Returns the specific modules to which the package is being open or null, if the package is open all modules which have readability to this module. * - * @return the specific modules to which the package is being exported + * @return the specific modules to which the package is being opened */ - public List getTargetModules() { - return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, "getTargetModules", Collections.EMPTY_LIST)); - } + List getTargetModules(); } - public static class ProvidesDirective extends Directive { + static class OpensDirectiveImpl extends Directive implements OpensDirective { - private ProvidesDirective(Object wrappedDirective) { + private OpensDirectiveImpl(Object wrappedDirective) { super(wrappedDirective); } + @Override + public PackageElementWrapper getPackage() { + return PackageElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, OPENS_DIRECTIVE_CLASS_NAME, "getPackage").get()); + } + + @Override + public List getTargetModules() { + return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, OPENS_DIRECTIVE_CLASS_NAME, "getTargetModules").get()); + } + + } + + public interface ProvidesDirective { + /** * Returns the service being provided * * @return the service being provided */ - public TypeElementWrapper getService(){ - return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getService", null)); - } + TypeElementWrapper getService(); /** * Returns the implementations of the service being provided. * * @return the implementations of the service being provided */ - public List getImplementations() { - List implementations = (ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, "getTargetModules", Collections.EMPTY_LIST)); - return implementations.stream().map(TypeElementWrapper::wrap).collect(Collectors.toList()); - } + List getImplementations(); } - public static class RequiresDirective extends Directive { + static class ProvidesDirectiveImpl extends Directive implements ProvidesDirective { - private RequiresDirective(Object wrappedDirective) { + private ProvidesDirectiveImpl(Object wrappedDirective) { super(wrappedDirective); } + @Override + public TypeElementWrapper getService() { + return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, PROVIDES_DIRECTIVE_CLASS_NAME, "getService").get()); + } + + @Override + public List getImplementations() { + List implementations = (ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, PROVIDES_DIRECTIVE_CLASS_NAME, "getImplementations").get()); + return implementations.stream().map(TypeElementWrapper::wrap).collect(Collectors.toList()); + } + + } + + public interface RequiresDirective { + /** * Returns the module that is required * * @return the module that is required */ - public ModuleElementWrapper getDependency(){ - return ModuleElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getDependency", null)); - } + ModuleElementWrapper getDependency(); /** * Returns whether or not this is a static dependency. + * * @return whether or not this is a static dependency. */ - public boolean isStatic() { - return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective,"isStatic",false); - } + boolean isStatic(); /** * Returns whether or not this is a transitive dependency. + * * @return whether or not this is a transitive dependency. */ - boolean isTransitive() { - return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective,"isTransitive",false); - } + boolean isTransitive(); } - public static class UsesDirective extends Directive { + static class RequiresDirectiveImpl extends Directive implements RequiresDirective { + - private UsesDirective(Object wrappedDirective) { + private RequiresDirectiveImpl(Object wrappedDirective) { super(wrappedDirective); } + @Override + public ModuleElementWrapper getDependency() { + return ModuleElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "getDependency").get()); + } + + + @Override + public boolean isStatic() { + return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "isStatic").get(); + } + + @Override + public boolean isTransitive() { + return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "isTransitive").get(); + } + + } + + public interface UsesDirective { + /** * Returns the service being used * * @return the service being used */ - public TypeElementWrapper getService(){ - return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, "getService", null)); + TypeElementWrapper getService(); + + + } + + public static class UsesDirectiveImpl extends Directive implements UsesDirective { + + private UsesDirectiveImpl(Object wrappedDirective) { + super(wrappedDirective); } + @Override + public TypeElementWrapper getService() { + return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, USES_DIRECTIVE_CLASS_NAME, "getService").get()); + } } @@ -227,21 +298,21 @@ private static Directive createDirective(Object instance) { } if (Directive.isExportDirective(instance)) { - return new ExportsDirective(instance); + return new ExportsDirectiveImpl(instance); } else if (Directive.isOpensDirective(instance)) { - return new OpensDirective(instance); + return new OpensDirectiveImpl(instance); } else if (Directive.isProvidesDirective(instance)) { - return new ProvidesDirective(instance); + return new ProvidesDirectiveImpl(instance); } else if (Directive.isRequiresDirective(instance)) { - return new RequiresDirective(instance); + return new RequiresDirectiveImpl(instance); } else if (Directive.isUsesDirective(instance)) { - return new UsesDirective(instance); + return new UsesDirectiveImpl(instance); } return null; } - private static List createDirectives (List directives) { + private static List createDirectives(List directives) { return directives.stream().map(e -> createDirective(e)).filter(Objects::nonNull).collect(Collectors.toList()); @@ -252,8 +323,8 @@ private ModuleElementWrapper(Element moduleElement) { } public String getQualifiedName() { - // default value not needed - return invokeParameterlessMethodOfElement("getQualifiedName", null).toString(); + Optional result = this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "getQualifiedName"); + return result.isPresent() ? result.get().toString() : ""; } public boolean hasQualifiedName(String name) { @@ -261,18 +332,19 @@ public boolean hasQualifiedName(String name) { } public boolean isOpen() { - // default value not needed - return this.invokeParameterlessMethodOfElement("isOpen", false); + Optional result = this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "isOpen"); + return result.orElse(false); } public boolean isUnnamed() { - // default value not needed - return this.invokeParameterlessMethodOfElement("isUnnamed", false); + Optional result = this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "isUnnamed"); + return result.orElse(false); } public List getDirectives() { - return createDirectives(this.>invokeParameterlessMethodOfElement("getDirectives", Collections.EMPTY_LIST)); + Optional> result = this.>invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "getDirectives"); + return createDirectives(result.isPresent() ? result.get() : Collections.EMPTY_LIST); } @@ -302,10 +374,10 @@ public static ModuleElementWrapper wrap(Element element) { * So this method will try to wrap all Elements of the passed list. It will drop those not being ModuleElements. * * @param moduleElements A List of ModuleElements. - * @return A list of ModuleElementWrapper of elements representing modules that could successfully wrapped, or an empty list. + * @return A list of ModuleElementWrapper of elements representing modules that could successfully be wrapped, or an empty list. */ public static List wrapList(List moduleElements) { - return moduleElements.stream().map(ModuleElementWrapper::new).filter(Objects::nonNull).collect(Collectors.toList()); + return moduleElements.stream().map(ModuleElementWrapper::wrap).filter(Objects::nonNull).collect(Collectors.toList()); } } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java index c41db307..5d745521 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java @@ -8,6 +8,10 @@ * Wrapper class for RecordComponentElementWrapper. */ public class RecordComponentElementWrapper extends ElementWrapper { + + private final static String RECORD_COMPONENT_ELEMENT_CLASS_NAME = "javax.lang.model.element.RecordComponentElement"; + + private RecordComponentElementWrapper(Element recordComponentElement) { super(recordComponentElement); } @@ -27,8 +31,7 @@ public TypeElementWrapper getEnclosingRecordTypeElement() { * @return the accessors wrapped ExecutableElement */ public ExecutableElementWrapper getAccessor() { - // doesn't use default value - return ExecutableElementWrapper.wrap(this.invokeParameterlessMethodOfElement("getAccessor", null)); + return ExecutableElementWrapper.wrap(this.invokeParameterlessMethodOfElement(RECORD_COMPONENT_ELEMENT_CLASS_NAME, "getAccessor").get()); } /** diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java index 9db9529f..0bcb029b 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java @@ -25,6 +25,8 @@ */ public class TypeElementWrapper extends ElementWrapper { + private final static String TYPE_ELEMENT_CLASS_NAME = "javax.lang.model.element.TypeElement"; + /** * Hidden constructor. * @@ -272,7 +274,7 @@ public List getRecordComponents() { if (!isRecord()) { return Collections.EMPTY_LIST; } - List recordComponentElements = this.invokeParameterlessMethodOfElement("getRecordComponents", Collections.EMPTY_LIST); + List recordComponentElements = this.>invokeParameterlessMethodOfElement(TYPE_ELEMENT_CLASS_NAME, "getRecordComponents").get(); return recordComponentElements.stream().map(RecordComponentElementWrapper::wrap).collect(Collectors.toList()); @@ -283,7 +285,7 @@ public List getRecordComponents() { * @return the permitted classes, or an empty list if there are none */ public List getPermittedSubclasses() { - List typeMirrors = this.>invokeParameterlessMethodOfElement("getPermittedSubclasses", Collections.EMPTY_LIST); + List typeMirrors = this.>invokeParameterlessMethodOfElement(TYPE_ELEMENT_CLASS_NAME, "getPermittedSubclasses").get(); return typeMirrors.stream().map(TypeMirrorWrapper::wrap).collect(Collectors.toList()); } diff --git a/tools/src/test/java/io/toolisticon/aptk/tools/wrapper/ModulesElementWrapperTest.java b/tools/src/test/java/io/toolisticon/aptk/tools/wrapper/ModulesElementWrapperTest.java new file mode 100644 index 00000000..63672ce4 --- /dev/null +++ b/tools/src/test/java/io/toolisticon/aptk/tools/wrapper/ModulesElementWrapperTest.java @@ -0,0 +1,60 @@ +package io.toolisticon.aptk.tools.wrapper; + +import io.toolisticon.aptk.common.ToolingProvider; +import io.toolisticon.cute.Cute; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +import javax.lang.model.element.Element; +import javax.tools.Tool; +import java.util.Arrays; +import java.util.Optional; + +/** + * Unit test for {@link ModuleElementWrapper}. + * Only handles wrapping part since this module is build with Java version <9. + */ +public class ModulesElementWrapperTest { + + @Test + public void test_invalidWrap () { + Cute.unitTest().when().unitTestWithoutPassIn(processingEnvironment -> { + try{ + ToolingProvider.setTooling(processingEnvironment); + + MatcherAssert.assertThat(ModuleElementWrapper.wrap((Element) TypeElementWrapper.getByClass(ModulesElementWrapperTest.class).get().unwrap()),Matchers.nullValue()); + } finally { + ToolingProvider.clearTooling(); + } + }).executeTest(); + } + + @Test + public void test_invalidToModuleElement () { + Cute.unitTest().when().unitTestWithoutPassIn(processingEnvironment -> { + try{ + ToolingProvider.setTooling(processingEnvironment); + + MatcherAssert.assertThat(ModuleElementWrapper.toModuleElement((ElementWrapper) TypeElementWrapper.getByClass(ModulesElementWrapperTest.class).get()),Matchers.nullValue()); + } finally { + ToolingProvider.clearTooling(); + } + }).executeTest(); + } + + @Test + public void test_invalidWrapOfList () { + Cute.unitTest().when().unitTestWithoutPassIn(processingEnvironment -> { + try{ + ToolingProvider.setTooling(processingEnvironment); + + MatcherAssert.assertThat(ModuleElementWrapper.wrapList(Arrays.asList( TypeElementWrapper.getByClass(ModulesElementWrapperTest.class).get().unwrap())),Matchers.empty()); + } finally { + ToolingProvider.clearTooling(); + } + }).executeTest(); + } + + +} From f69d557c752c1deb598b402a75366fe2f931aece Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 01:41:19 +0200 Subject: [PATCH 07/14] [#148] Added tests for RecordComponentWrapper --- .../io/toolisticon/aptk/tools/wrapper/Java16Tests.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/integrationtest/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java b/integrationtest/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java index 74574d6a..6bb9b3d8 100644 --- a/integrationtest/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java +++ b/integrationtest/java16/src/test/java/io/toolisticon/aptk/tools/wrapper/Java16Tests.java @@ -106,8 +106,8 @@ public void test_recordComponent_isTypeElement() { } - - public void test_recordComponent_simpleName() { + @Test + public void test_recordComponent_accessWrapperMethods() { Cute.unitTest().when().passInElement().fromClass(MyRecord.class).intoUnitTest((processingEnvironment, element) -> { try { ToolingProvider.setTooling(processingEnvironment); @@ -115,6 +115,10 @@ public void test_recordComponent_simpleName() { RecordComponentElementWrapper elementWrapper = typeElement.getRecordComponents().get(0); MatcherAssert.assertThat(elementWrapper.getSimpleName(), Matchers.is("name")); + MatcherAssert.assertThat("Must be methods", elementWrapper.getAccessor().isMethod()); + MatcherAssert.assertThat(elementWrapper.getEnclosingRecordTypeElement().getQualifiedName(), Matchers.is(MyRecord.class.getCanonicalName())); + MatcherAssert.assertThat(TypeElementWrapper.toTypeElement(elementWrapper.getEnclosingElement().get()).getQualifiedName(), Matchers.is(MyRecord.class.getCanonicalName())); + } finally { ToolingProvider.clearTooling(); @@ -124,6 +128,7 @@ public void test_recordComponent_simpleName() { } + @Test public void test_recordComponent_filtering_byTypeElement() { Cute.unitTest().when((processingEnvironment) -> { From 2f6f487989d3158a22f783821a956eb13e39db12 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 13:58:15 +0200 Subject: [PATCH 08/14] [#148] Removed Optional from reflective calls and added workaround for getAccessor --- .../aptk/tools/wrapper/ElementWrapper.java | 27 +++++++++--- .../tools/wrapper/ModuleElementWrapper.java | 43 ++++++++----------- .../RecordComponentElementWrapper.java | 24 +++++++++-- .../tools/wrapper/TypeElementWrapper.java | 12 +++++- 4 files changed, 71 insertions(+), 35 deletions(-) diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java index cb0523d5..99856592 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ElementWrapper.java @@ -16,7 +16,7 @@ import javax.lang.model.element.TypeElement; import java.lang.annotation.Annotation; import java.lang.annotation.Repeatable; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -96,6 +96,7 @@ public boolean hasSimplePackageName(String name) { /** * Gets the module of the wrapped element + * * @return an optional containing the wrapped module element */ public Optional getModule() { @@ -764,19 +765,33 @@ public static ExecutableElementWrapper toExecutableElementWrapper(ElementWrapper return ExecutableElementWrapper.wrap(ElementUtils.CastElement.castToExecutableElement(wrapper.unwrap())); } - protected Optional invokeParameterlessMethodOfElement(String interfaceName, String methodName) { + + + protected TARGET_TYPE invokeParameterlessMethodOfElement(String interfaceName, String methodName) { return ElementWrapper.invokeParameterlessMethodOfElement(element, interfaceName, methodName); } - protected static Optional invokeParameterlessMethodOfElement(Object instance, String interfaceName, String methodName) { + protected static TARGET_TYPE invokeParameterlessMethodOfElement(Object instance, String interfaceName, String methodName) { try { Class interfaceClass = Class.forName(interfaceName); - - return Optional.ofNullable((TARGET_TYPE) interfaceClass.getMethod(methodName).invoke(instance)); + return (TARGET_TYPE) interfaceClass.getMethod(methodName).invoke(instance); } catch (Exception e) { - return Optional.empty(); + // This usually shouldn't be thrown since the caller must ensure that the call is available in the used java version + throw new IllegalStateException("Couldn't invoke " + interfaceName + "." + methodName + "()", e); } } + protected boolean hasMethod(String interfaceName, String methodName) { + try { + + Class interfaceClass = Class.forName(interfaceName); + Method method = interfaceClass.getMethod(methodName); + return true; + + } catch (Exception e) { + // This usually shouldn't be thrown since the caller must ensure that the call is available in the used java version + return false; + } + } } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java index 7e3e2749..b1653979 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/ModuleElementWrapper.java @@ -39,7 +39,7 @@ public boolean isExportDirective() { } private static boolean isExportDirective(Object instance) { - return "EXPORTS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); + return "EXPORTS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").toString()); } public ExportsDirective toExportsDirective() { @@ -52,7 +52,7 @@ public boolean isOpensDirective() { } private static boolean isOpensDirective(Object instance) { - return "OPENS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); + return "OPENS".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").toString()); } public OpensDirective toOpensDirective() { @@ -64,7 +64,7 @@ public boolean isProvidesDirective() { } private static boolean isProvidesDirective(Object instance) { - return "PROVIDES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); + return "PROVIDES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").toString()); } public ProvidesDirective toProvidesDirective() { @@ -76,7 +76,7 @@ public boolean isRequiresDirective() { } private static boolean isRequiresDirective(Object instance) { - return "REQUIRES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); + return "REQUIRES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").toString()); } public RequiresDirective toRequiresDirective() { @@ -88,7 +88,7 @@ public boolean isUsesDirective() { } private static boolean isUsesDirective(Object instance) { - return "USES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").get().toString()); + return "USES".equals(ElementWrapper.invokeParameterlessMethodOfElement(instance, DIRECTIVE_CLASS_NAME, "getKind").toString()); } @@ -127,13 +127,12 @@ private ExportsDirectiveImpl(Object wrappedDirective) { @Override public PackageElementWrapper getPackage() { - Optional result = ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, EXPORTS_DIRECTIVE_CLASS_NAME, "getPackage"); - return PackageElementWrapper.wrap(result.get()); + return PackageElementWrapper.wrap( ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, EXPORTS_DIRECTIVE_CLASS_NAME, "getPackage")); } @Override public List getTargetModules() { - return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, EXPORTS_DIRECTIVE_CLASS_NAME, "getTargetModules").get()); + return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, EXPORTS_DIRECTIVE_CLASS_NAME, "getTargetModules")); } @@ -167,12 +166,12 @@ private OpensDirectiveImpl(Object wrappedDirective) { @Override public PackageElementWrapper getPackage() { - return PackageElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, OPENS_DIRECTIVE_CLASS_NAME, "getPackage").get()); + return PackageElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, OPENS_DIRECTIVE_CLASS_NAME, "getPackage")); } @Override public List getTargetModules() { - return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, OPENS_DIRECTIVE_CLASS_NAME, "getTargetModules").get()); + return ModuleElementWrapper.wrapList(ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, OPENS_DIRECTIVE_CLASS_NAME, "getTargetModules")); } } @@ -204,12 +203,12 @@ private ProvidesDirectiveImpl(Object wrappedDirective) { @Override public TypeElementWrapper getService() { - return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, PROVIDES_DIRECTIVE_CLASS_NAME, "getService").get()); + return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, PROVIDES_DIRECTIVE_CLASS_NAME, "getService")); } @Override public List getImplementations() { - List implementations = (ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, PROVIDES_DIRECTIVE_CLASS_NAME, "getImplementations").get()); + List implementations = (ElementWrapper.>invokeParameterlessMethodOfElement(wrappedDirective, PROVIDES_DIRECTIVE_CLASS_NAME, "getImplementations")); return implementations.stream().map(TypeElementWrapper::wrap).collect(Collectors.toList()); } @@ -250,18 +249,18 @@ private RequiresDirectiveImpl(Object wrappedDirective) { @Override public ModuleElementWrapper getDependency() { - return ModuleElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "getDependency").get()); + return ModuleElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "getDependency")); } @Override public boolean isStatic() { - return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "isStatic").get(); + return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "isStatic"); } @Override public boolean isTransitive() { - return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "isTransitive").get(); + return ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, REQUIRES_DIRECTIVE_CLASS_NAME, "isTransitive"); } } @@ -286,7 +285,7 @@ private UsesDirectiveImpl(Object wrappedDirective) { @Override public TypeElementWrapper getService() { - return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, USES_DIRECTIVE_CLASS_NAME, "getService").get()); + return TypeElementWrapper.wrap(ElementWrapper.invokeParameterlessMethodOfElement(wrappedDirective, USES_DIRECTIVE_CLASS_NAME, "getService")); } @@ -323,8 +322,7 @@ private ModuleElementWrapper(Element moduleElement) { } public String getQualifiedName() { - Optional result = this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "getQualifiedName"); - return result.isPresent() ? result.get().toString() : ""; + return this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "getQualifiedName").toString(); } public boolean hasQualifiedName(String name) { @@ -332,19 +330,16 @@ public boolean hasQualifiedName(String name) { } public boolean isOpen() { - Optional result = this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "isOpen"); - return result.orElse(false); + return this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "isOpen"); } public boolean isUnnamed() { - Optional result = this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "isUnnamed"); - return result.orElse(false); + return this.invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "isUnnamed"); } public List getDirectives() { - Optional> result = this.>invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "getDirectives"); - return createDirectives(result.isPresent() ? result.get() : Collections.EMPTY_LIST); + return createDirectives(this.>invokeParameterlessMethodOfElement(MODULE_ELEMENT_CLASS_NAME, "getDirectives")); } diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java index 5d745521..6643952a 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/RecordComponentElementWrapper.java @@ -1,8 +1,11 @@ package io.toolisticon.aptk.tools.wrapper; +import io.toolisticon.aptk.tools.corematcher.AptkCoreMatchers; + import javax.lang.model.element.Element; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; +import java.util.List; /** * Wrapper class for RecordComponentElementWrapper. @@ -27,15 +30,30 @@ public TypeElementWrapper getEnclosingRecordTypeElement() { /** * Wraps the getAccessor method, but returns a ExecutableElementWrapper - * - * @return the accessors wrapped ExecutableElement + * !!! WARNING THERE SEEMS TO BE DIFFERENT BEHAVIOR BETWEEN DIFFERENT JDK DISTRIBUTIONS !!! + * So it will look up the accessor manually if necessary + * @return the accessors wrapped ExecutableElement, might return null if even the workaround doesn't work */ public ExecutableElementWrapper getAccessor() { - return ExecutableElementWrapper.wrap(this.invokeParameterlessMethodOfElement(RECORD_COMPONENT_ELEMENT_CLASS_NAME, "getAccessor").get()); + // safe to call since it's guaranteed that the wrapped element is a RecordComponentElement + ExecutableElement executableElement = this.invokeParameterlessMethodOfElement(RECORD_COMPONENT_ELEMENT_CLASS_NAME, "getAccessor"); + + return executableElement != null ? ExecutableElementWrapper.wrap(executableElement) : determineAccessorWorkaround(); + } + + private ExecutableElementWrapper determineAccessorWorkaround(){ + List results = this.getEnclosingRecordTypeElement().filterEnclosedElements() + .applyFilter(AptkCoreMatchers.IS_METHOD) + .applyFilter(AptkCoreMatchers.BY_NAME).filterByOneOf(getSimpleName()) + .applyFilter(AptkCoreMatchers.HAS_NO_PARAMETERS) + .getResult(); + + return results.isEmpty() ? null : ExecutableElementWrapper.wrap(results.get(0)); } /** * Re-wraps an ElementWrapper to a RecordComponentElementWrapper. + * * @param element the wrapper to re-wrap * @return The RecordComponentElementWrapper or null if the passed ElementWrapper doesn't wrap a RecordComponentElement */ diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java index 0bcb029b..b1070720 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java @@ -271,10 +271,11 @@ public List getEnumValues() { */ public List getRecordComponents() { + // This method is available from Java 16 - the introduction of records, so this check is sufficient to prevent reflective calling of method if (!isRecord()) { return Collections.EMPTY_LIST; } - List recordComponentElements = this.>invokeParameterlessMethodOfElement(TYPE_ELEMENT_CLASS_NAME, "getRecordComponents").get(); + List recordComponentElements = this.>invokeParameterlessMethodOfElement(TYPE_ELEMENT_CLASS_NAME, "getRecordComponents"); return recordComponentElements.stream().map(RecordComponentElementWrapper::wrap).collect(Collectors.toList()); @@ -285,7 +286,14 @@ public List getRecordComponents() { * @return the permitted classes, or an empty list if there are none */ public List getPermittedSubclasses() { - List typeMirrors = this.>invokeParameterlessMethodOfElement(TYPE_ELEMENT_CLASS_NAME, "getPermittedSubclasses").get(); + + // must make sure that method exists, otherwise return the default value + if (hasMethod(TYPE_ELEMENT_CLASS_NAME, "getPermittedSubclasses")) { + // TODO MUST CHECK WHAT SHOULD BE RETURNED FOR NON SEALED CLASSES! + return Collections.EMPTY_LIST; + } + + List typeMirrors = this.>invokeParameterlessMethodOfElement(TYPE_ELEMENT_CLASS_NAME, "getPermittedSubclasses"); return typeMirrors.stream().map(TypeMirrorWrapper::wrap).collect(Collectors.toList()); } From e604a44f30cca54335c929c568d581fa88204ba8 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 14:13:38 +0200 Subject: [PATCH 09/14] [#148] added build for oracle jdk --- .github/workflows/default_oracle.yml | 35 ++++++++++++++++++++++++++++ .github/workflows/jacoco.yml | 4 ++-- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/default_oracle.yml diff --git a/.github/workflows/default_oracle.yml b/.github/workflows/default_oracle.yml new file mode 100644 index 00000000..201845ee --- /dev/null +++ b/.github/workflows/default_oracle.yml @@ -0,0 +1,35 @@ +name: default + +on: + push: + branches: + - '*' + - '**/*' + - '!master' + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest,macos-latest,windows-latest ] + java: [ '8', '11', '17', '21' ] + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up JDK ${{ matrix.java }} + uses: actions/setup-java@v4 + with: + distribution: 'oracle' + java-version: ${{ matrix.java }} + cache: 'maven' + + + - name: Prepare mvnw + run: chmod +x ./mvnw + + - name: Build + run: ./mvnw clean package + diff --git a/.github/workflows/jacoco.yml b/.github/workflows/jacoco.yml index 46456753..fd384fc6 100644 --- a/.github/workflows/jacoco.yml +++ b/.github/workflows/jacoco.yml @@ -15,10 +15,10 @@ jobs: - name: Checkout code uses: actions/checkout@v1 - - name: Set up JDK 9 + - name: Set up JDK 16 uses: actions/setup-java@v1 with: - java-version: 9 + java-version: 16 - name: Cache .m2 uses: actions/cache@v1 From e7dba0b3ffb31b8b7eaed52ce26bc339bace44f2 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 14:19:10 +0200 Subject: [PATCH 10/14] [#148] added build for oracle and temurin jdk --- .github/workflows/default.yml | 13 ++++------ .github/workflows/default_oracle.yml | 4 +-- .github/workflows/default_temurin.yml | 35 +++++++++++++++++++++++++++ 3 files changed, 42 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/default_temurin.yml diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index 02e7bba3..ae150afc 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -20,17 +20,12 @@ jobs: uses: actions/checkout@v1 - name: Set up JDK ${{ matrix.java }} - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: + distribution: 'zulu' java-version: ${{ matrix.java }} + cache: 'maven' - - name: Cache .m2 - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven - name: Prepare mvnw run: chmod +x ./mvnw @@ -38,3 +33,5 @@ jobs: - name: Build run: ./mvnw clean package + + diff --git a/.github/workflows/default_oracle.yml b/.github/workflows/default_oracle.yml index 201845ee..d6892c9b 100644 --- a/.github/workflows/default_oracle.yml +++ b/.github/workflows/default_oracle.yml @@ -1,4 +1,4 @@ -name: default +name: default_oracle on: push: @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest,macos-latest,windows-latest ] - java: [ '8', '11', '17', '21' ] + java: [ '17', '21' ] steps: - name: Checkout Code diff --git a/.github/workflows/default_temurin.yml b/.github/workflows/default_temurin.yml new file mode 100644 index 00000000..04877f37 --- /dev/null +++ b/.github/workflows/default_temurin.yml @@ -0,0 +1,35 @@ +name: default_temurin + +on: + push: + branches: + - '*' + - '**/*' + - '!master' + +jobs: + build: + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ ubuntu-latest,macos-latest,windows-latest ] + java: [ '8', '11', '17', '21' ] + + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Set up JDK ${{ matrix.java }} + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: ${{ matrix.java }} + cache: 'maven' + + + - name: Prepare mvnw + run: chmod +x ./mvnw + + - name: Build + run: ./mvnw clean package + From f79ba2a3bb5afdbeb73c49048b4389ace4ec6941 Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 16:25:30 +0200 Subject: [PATCH 11/14] [#148] enable builds with higher jdks by setting mockito versions via java version related profiles --- pom.xml | 127 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 106 insertions(+), 21 deletions(-) diff --git a/pom.xml b/pom.xml index 50e61fd0..cacf3f49 100644 --- a/pom.xml +++ b/pom.xml @@ -58,11 +58,6 @@ 2017 - - 3.6.0 - - - https://github.com/toolisticon/aptk/issues GitHub Issues @@ -92,7 +87,8 @@ 4.13.2 2.2 - 4.3.1 + 4.11.0 + 5.11.0 https://oss.sonatype.org/content/repositories/snapshots/ @@ -202,18 +198,6 @@ - - org.codehaus.mojo - build-helper-maven-plugin - ${maven-build-helper-plugin.version} - - - - - org.apache.maven.plugins - maven-source-plugin - ${maven-source-plugin.version} - com.amashchenko.maven.plugin @@ -559,6 +543,19 @@ [1.8,9) + + + + + org.mockito + mockito-core + ${mockito.version} + test + + + + + @@ -573,7 +570,7 @@ - check_java17 + check_java8 test @@ -611,9 +608,22 @@ jdkgreaterthan8 - [9,99) + [9,11) + + + + + org.mockito + mockito-core + ${mockito.version} + test + + + + + @@ -671,6 +681,82 @@ + + jdkgreaterthan11 + + [11,99) + + + + + + + org.mockito + mockito-core + ${mockito_jdk11.version} + test + + + + + + + + + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + 1.18 + + + + com.sun.source.util.Trees + com.sun.source.tree.* + + + + + + + + check_java18 + + test + + + check + + + + + io.toolisticon.cute:* + + + + org.codehaus.mojo.signature + java18 + 1.0 + + + + + + + + + + + + + + + + + + @@ -707,7 +793,6 @@ org.mockito mockito-core - ${mockito.version} test From fbdd75170b22854b28575a94b47b8e262893e3ca Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 16:36:56 +0200 Subject: [PATCH 12/14] [#148] limit builds on zulu to LTS versions --- .github/workflows/default.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index ae150afc..71b4bcaf 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: os: [ ubuntu-latest,macos-latest,windows-latest ] - java: [ 8.0.x, 9.0.x, 11.0.x, 12.0.x, 13.0.x, 14.0.x, 15.0.x, 16.0.x, 17.0.x ] + java: [ '8', '11', '17', '21' ] steps: - name: Checkout Code From e731e079e10be9effbbfb4290c0534af4052dfda Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 22:16:36 +0200 Subject: [PATCH 13/14] [#148] added tests for sealed classes feature --- integrationtest/java17/pom.xml | 94 +++++++++++++++++++ .../aptk/tools/wrapper/Java17Tests.java | 68 ++++++++++++++ integrationtest/pom.xml | 13 +++ 3 files changed, 175 insertions(+) create mode 100644 integrationtest/java17/pom.xml create mode 100644 integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java diff --git a/integrationtest/java17/pom.xml b/integrationtest/java17/pom.xml new file mode 100644 index 00000000..8dac5b51 --- /dev/null +++ b/integrationtest/java17/pom.xml @@ -0,0 +1,94 @@ + + 4.0.0 + + aptk-tools-java17 + jar + + + io.toolisticon.aptk + integrationtest-parent + 0.24.1-148_records-SNAPSHOT + + + aptk-tools-java17 + + + + + + io.toolisticon.aptk + aptk-tools + + + + + + + + + + + maven-enforcer-plugin + + + enforce + + enforce + + + + + [3.0.4,) + + + 9 + + + false + + * + + + io.toolisticon.aptk:aptk-tools:* + *:*:*:*:test:* + *:*:*:*:provided:* + + + + + + + + + + maven-compiler-plugin + + 16 + 16 + + + + + org.codehaus.mojo + animal-sniffer-maven-plugin + + true + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + + + + + + diff --git a/integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java b/integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java new file mode 100644 index 00000000..c97fe934 --- /dev/null +++ b/integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java @@ -0,0 +1,68 @@ +package io.toolisticon.aptk.tools.wrapper; + +import io.toolisticon.aptk.common.ToolingProvider; +import io.toolisticon.cute.Cute; +import io.toolisticon.cute.PassIn; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +import javax.lang.model.element.TypeElement; +import java.util.stream.Collectors; + +public class Java17Tests { + + + @Test + public void test_sealedClassesFeature_unsealed() { + Cute.unitTest().when().passInElement().fromClass(Java17Tests.class).intoUnitTest((processingEnvironment, element) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + + TypeElementWrapper elementWrapper = TypeElementWrapper.wrap(element); + + MatcherAssert.assertThat(elementWrapper.getPermittedSubclasses(), Matchers.empty()); + MatcherAssert.assertThat(element.getPermittedSubclasses(), Matchers.empty()); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + + + static final class AllowedClass extends SealedClass { + + } + + @PassIn + static sealed class SealedClass permits AllowedClass{ + + } + + + + @Test + public void test_sealedClassesFeature_sealed() { + Cute.unitTest().when().passInElement().fromClass(SealedClass.class).intoUnitTest((processingEnvironment, element) -> { + try { + ToolingProvider.setTooling(processingEnvironment); + + TypeElementWrapper elementWrapper = TypeElementWrapper.wrap(element); + + MatcherAssert.assertThat(elementWrapper.getPermittedSubclasses().stream().map(e -> e.getQualifiedName()).collect(Collectors.toSet()), Matchers.contains(SealedClass.class.getCanonicalName())); + MatcherAssert.assertThat(element.getPermittedSubclasses().stream().map(e -> e.toString()).collect(Collectors.toSet()), , Matchers.contains(SealedClass.class.getCanonicalName())); + + } finally { + ToolingProvider.clearTooling(); + } + + }).thenExpectThat().compilationSucceeds().executeTest(); + + } + + +} diff --git a/integrationtest/pom.xml b/integrationtest/pom.xml index 2a587340..a168efd2 100644 --- a/integrationtest/pom.xml +++ b/integrationtest/pom.xml @@ -38,6 +38,19 @@ + + java-17 + + [17,) + + + + java9 + java16 + java17 + + + From ee1fd3aba4d54424f39357b90df5113fc740c68b Mon Sep 17 00:00:00 2001 From: Tobias Stamann Date: Thu, 11 Apr 2024 22:23:00 +0200 Subject: [PATCH 14/14] [#148] added tests for sealed classes feature --- .github/workflows/default.yml | 2 +- .github/workflows/dropStaging.yml | 8 +++++--- .github/workflows/jacoco.yml | 17 ++++++----------- .github/workflows/release.yml | 14 ++++---------- integrationtest/java16/pom.xml | 2 +- integrationtest/java17/pom.xml | 6 +++--- .../aptk/tools/wrapper/Java17Tests.java | 14 ++++++-------- .../aptk/tools/wrapper/TypeElementWrapper.java | 2 +- 8 files changed, 27 insertions(+), 38 deletions(-) diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml index 71b4bcaf..2d9f8e48 100644 --- a/.github/workflows/default.yml +++ b/.github/workflows/default.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Set up JDK ${{ matrix.java }} uses: actions/setup-java@v4 diff --git a/.github/workflows/dropStaging.yml b/.github/workflows/dropStaging.yml index dd930de1..7836d736 100644 --- a/.github/workflows/dropStaging.yml +++ b/.github/workflows/dropStaging.yml @@ -17,13 +17,15 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 # Setup JDK and Maven - name: Set up JDK 9 - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: - java-version: 9 + distribution: 'zulu' + java-version: 17 + cache: 'maven' server-id: sonatype-nexus-staging server-username: OSS_CENTRAL_USERNAME # env variable for Maven Central server-password: OSS_CENTRAL_PASSWORD # env variable for Maven Central diff --git a/.github/workflows/jacoco.yml b/.github/workflows/jacoco.yml index fd384fc6..9661e777 100644 --- a/.github/workflows/jacoco.yml +++ b/.github/workflows/jacoco.yml @@ -13,20 +13,15 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v1 + uses: actions/checkout@v4 - - name: Set up JDK 16 - uses: actions/setup-java@v1 + - name: Set up JDK 17 + uses: actions/setup-java@v4 with: - java-version: 16 + distribution: 'zulu' + java-version: 17 + cache: 'maven' - - name: Cache .m2 - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven - name: Prepare mvnw run: chmod +x ./mvnw diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e3e3739c..718bbf49 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,15 +11,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v1 - - - name: Cache .m2 - uses: actions/cache@v1 - with: - path: ~/.m2/repository - key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }} - restore-keys: | - ${{ runner.os }}-maven + uses: actions/checkout@v4 # Get GPG private key into GPG - name: Import GPG Owner Trust @@ -29,9 +21,11 @@ jobs: # Setup JDK and Maven - name: Set up JDK 17 - uses: actions/setup-java@v1 + uses: actions/setup-java@v4 with: + distribution: 'zulu' java-version: 17 + cache: 'maven' server-id: sonatype-nexus-staging server-username: OSS_CENTRAL_USERNAME # env variable for Maven Central server-password: OSS_CENTRAL_PASSWORD # env variable for Maven Central diff --git a/integrationtest/java16/pom.xml b/integrationtest/java16/pom.xml index 0e86bce7..9c9e9b22 100644 --- a/integrationtest/java16/pom.xml +++ b/integrationtest/java16/pom.xml @@ -42,7 +42,7 @@ [3.0.4,) - 9 + 16 false diff --git a/integrationtest/java17/pom.xml b/integrationtest/java17/pom.xml index 8dac5b51..a5c9c710 100644 --- a/integrationtest/java17/pom.xml +++ b/integrationtest/java17/pom.xml @@ -42,7 +42,7 @@ [3.0.4,) - 9 + 17 false @@ -64,8 +64,8 @@ maven-compiler-plugin - 16 - 16 + 17 + 17 diff --git a/integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java b/integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java index c97fe934..c78b9c17 100644 --- a/integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java +++ b/integrationtest/java17/src/test/java/io/toolisticon/aptk/tools/wrapper/Java17Tests.java @@ -15,14 +15,14 @@ public class Java17Tests { @Test public void test_sealedClassesFeature_unsealed() { - Cute.unitTest().when().passInElement().fromClass(Java17Tests.class).intoUnitTest((processingEnvironment, element) -> { + Cute.unitTest().when((processingEnvironment) -> { try { ToolingProvider.setTooling(processingEnvironment); - TypeElementWrapper elementWrapper = TypeElementWrapper.wrap(element); + TypeElementWrapper elementWrapper = TypeElementWrapper.getByClass(Java17Tests.class).get(); MatcherAssert.assertThat(elementWrapper.getPermittedSubclasses(), Matchers.empty()); - MatcherAssert.assertThat(element.getPermittedSubclasses(), Matchers.empty()); + MatcherAssert.assertThat(elementWrapper.unwrap().getPermittedSubclasses(), Matchers.empty()); } finally { ToolingProvider.clearTooling(); @@ -33,18 +33,16 @@ public void test_sealedClassesFeature_unsealed() { } - static final class AllowedClass extends SealedClass { } @PassIn - static sealed class SealedClass permits AllowedClass{ + static sealed class SealedClass permits AllowedClass { } - @Test public void test_sealedClassesFeature_sealed() { Cute.unitTest().when().passInElement().fromClass(SealedClass.class).intoUnitTest((processingEnvironment, element) -> { @@ -53,8 +51,8 @@ public void test_sealedClassesFeature_sealed() { TypeElementWrapper elementWrapper = TypeElementWrapper.wrap(element); - MatcherAssert.assertThat(elementWrapper.getPermittedSubclasses().stream().map(e -> e.getQualifiedName()).collect(Collectors.toSet()), Matchers.contains(SealedClass.class.getCanonicalName())); - MatcherAssert.assertThat(element.getPermittedSubclasses().stream().map(e -> e.toString()).collect(Collectors.toSet()), , Matchers.contains(SealedClass.class.getCanonicalName())); + MatcherAssert.assertThat(elementWrapper.getPermittedSubclasses().stream().map(e -> e.getQualifiedName()).collect(Collectors.toSet()), Matchers.contains(AllowedClass.class.getCanonicalName())); + MatcherAssert.assertThat(element.getPermittedSubclasses().stream().map(e -> e.toString()).collect(Collectors.toSet()), Matchers.contains(AllowedClass.class.getCanonicalName())); } finally { ToolingProvider.clearTooling(); diff --git a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java index b1070720..dffc6504 100644 --- a/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java +++ b/tools/src/main/java/io/toolisticon/aptk/tools/wrapper/TypeElementWrapper.java @@ -288,7 +288,7 @@ public List getRecordComponents() { public List getPermittedSubclasses() { // must make sure that method exists, otherwise return the default value - if (hasMethod(TYPE_ELEMENT_CLASS_NAME, "getPermittedSubclasses")) { + if (!hasMethod(TYPE_ELEMENT_CLASS_NAME, "getPermittedSubclasses")) { // TODO MUST CHECK WHAT SHOULD BE RETURNED FOR NON SEALED CLASSES! return Collections.EMPTY_LIST; }