From 2d1ae58f9e419ce15a0400fb6395a0987a70c55b Mon Sep 17 00:00:00 2001 From: Olaf Kaiser Date: Mon, 19 Feb 2024 23:08:50 +0100 Subject: [PATCH 1/5] updating poms for 5.2.4-SNAPSHOT development --- api/pom.xml | 2 +- core/pom.xml | 2 +- delivery-aem/pom.xml | 2 +- delivery-sling/pom.xml | 2 +- pom.xml | 2 +- spring/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 71ede7b9..dbf0240d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -14,7 +14,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.4-SNAPSHOT diff --git a/core/pom.xml b/core/pom.xml index e47dc799..4989483a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -15,7 +15,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.4-SNAPSHOT diff --git a/delivery-aem/pom.xml b/delivery-aem/pom.xml index 110e1a65..f1f88ecb 100644 --- a/delivery-aem/pom.xml +++ b/delivery-aem/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.4-SNAPSHOT diff --git a/delivery-sling/pom.xml b/delivery-sling/pom.xml index 96a0497d..fba135d3 100644 --- a/delivery-sling/pom.xml +++ b/delivery-sling/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.4-SNAPSHOT diff --git a/pom.xml b/pom.xml index 2204d4f1..318cce89 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.4-SNAPSHOT NEBA parent POM pom diff --git a/spring/pom.xml b/spring/pom.xml index 70981751..58f2a7ad 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -11,7 +11,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.4-SNAPSHOT From 93910b70ff451825cb908dcb39b32bbfefd391e7 Mon Sep 17 00:00:00 2001 From: Olaf Kaiser Date: Mon, 19 Feb 2024 23:09:07 +0100 Subject: [PATCH 2/5] updating poms for branch'release/5.2.3' with non-snapshot versions --- api/pom.xml | 2 +- core/pom.xml | 2 +- delivery-aem/pom.xml | 2 +- delivery-sling/pom.xml | 2 +- pom.xml | 2 +- spring/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 71ede7b9..21b6a920 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -14,7 +14,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.3 diff --git a/core/pom.xml b/core/pom.xml index e47dc799..aa4e8eab 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -15,7 +15,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.3 diff --git a/delivery-aem/pom.xml b/delivery-aem/pom.xml index 110e1a65..3233da66 100644 --- a/delivery-aem/pom.xml +++ b/delivery-aem/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.3 diff --git a/delivery-sling/pom.xml b/delivery-sling/pom.xml index 96a0497d..a69d1894 100644 --- a/delivery-sling/pom.xml +++ b/delivery-sling/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.3 diff --git a/pom.xml b/pom.xml index 2204d4f1..d2279a7c 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.3 NEBA parent POM pom diff --git a/spring/pom.xml b/spring/pom.xml index 70981751..5561ca0c 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -11,7 +11,7 @@ io.neba io.neba.neba-parent - 5.2.3-SNAPSHOT + 5.2.3 From d9f04a8f149e762f40179f20e832b95fd4decb9f Mon Sep 17 00:00:00 2001 From: Olaf Kaiser Date: Mon, 19 Feb 2024 23:12:03 +0100 Subject: [PATCH 3/5] updating develop poms to master versions to avoid merge conflicts --- api/pom.xml | 2 +- core/pom.xml | 2 +- delivery-aem/pom.xml | 2 +- delivery-sling/pom.xml | 2 +- pom.xml | 2 +- spring/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index dbf0240d..21b6a920 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -14,7 +14,7 @@ io.neba io.neba.neba-parent - 5.2.4-SNAPSHOT + 5.2.3 diff --git a/core/pom.xml b/core/pom.xml index 4989483a..aa4e8eab 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -15,7 +15,7 @@ io.neba io.neba.neba-parent - 5.2.4-SNAPSHOT + 5.2.3 diff --git a/delivery-aem/pom.xml b/delivery-aem/pom.xml index f1f88ecb..3233da66 100644 --- a/delivery-aem/pom.xml +++ b/delivery-aem/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.4-SNAPSHOT + 5.2.3 diff --git a/delivery-sling/pom.xml b/delivery-sling/pom.xml index fba135d3..a69d1894 100644 --- a/delivery-sling/pom.xml +++ b/delivery-sling/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.4-SNAPSHOT + 5.2.3 diff --git a/pom.xml b/pom.xml index 318cce89..d2279a7c 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.neba io.neba.neba-parent - 5.2.4-SNAPSHOT + 5.2.3 NEBA parent POM pom diff --git a/spring/pom.xml b/spring/pom.xml index 58f2a7ad..5561ca0c 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -11,7 +11,7 @@ io.neba io.neba.neba-parent - 5.2.4-SNAPSHOT + 5.2.3 From 792252feaab105ae82d79cbd1799790e89baed84 Mon Sep 17 00:00:00 2001 From: Olaf Kaiser Date: Mon, 19 Feb 2024 23:12:08 +0100 Subject: [PATCH 4/5] Updating develop poms back to pre merge state --- api/pom.xml | 2 +- core/pom.xml | 2 +- delivery-aem/pom.xml | 2 +- delivery-sling/pom.xml | 2 +- pom.xml | 2 +- spring/pom.xml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/api/pom.xml b/api/pom.xml index 21b6a920..dbf0240d 100644 --- a/api/pom.xml +++ b/api/pom.xml @@ -14,7 +14,7 @@ io.neba io.neba.neba-parent - 5.2.3 + 5.2.4-SNAPSHOT diff --git a/core/pom.xml b/core/pom.xml index aa4e8eab..4989483a 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -15,7 +15,7 @@ io.neba io.neba.neba-parent - 5.2.3 + 5.2.4-SNAPSHOT diff --git a/delivery-aem/pom.xml b/delivery-aem/pom.xml index 3233da66..f1f88ecb 100644 --- a/delivery-aem/pom.xml +++ b/delivery-aem/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.3 + 5.2.4-SNAPSHOT diff --git a/delivery-sling/pom.xml b/delivery-sling/pom.xml index a69d1894..fba135d3 100644 --- a/delivery-sling/pom.xml +++ b/delivery-sling/pom.xml @@ -9,7 +9,7 @@ io.neba io.neba.neba-parent - 5.2.3 + 5.2.4-SNAPSHOT diff --git a/pom.xml b/pom.xml index d2279a7c..318cce89 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 io.neba io.neba.neba-parent - 5.2.3 + 5.2.4-SNAPSHOT NEBA parent POM pom diff --git a/spring/pom.xml b/spring/pom.xml index 5561ca0c..58f2a7ad 100644 --- a/spring/pom.xml +++ b/spring/pom.xml @@ -11,7 +11,7 @@ io.neba io.neba.neba-parent - 5.2.3 + 5.2.4-SNAPSHOT From c3dd1fb3d181699153c531210ef5949941a6230c Mon Sep 17 00:00:00 2001 From: Olaf Kaiser Date: Wed, 26 Jun 2024 10:09:35 +0200 Subject: [PATCH 5/5] neba-445 Support mixing neba core and spring -based models in the same pkg #445 neba-446 Support @ResourceModel as meta-annotation for neba core models #446 --- .../factory/ClassBasedModelDefinition.java | 3 +- .../resourcemodels/factory/ModelFactory.java | 22 ++-- .../factory/ModelFactoryTest.java | 103 +++++++++++++++--- .../springframework/stereotype/Component.java | 31 ++++++ 4 files changed, 127 insertions(+), 32 deletions(-) create mode 100644 core/src/test/java/org/springframework/stereotype/Component.java diff --git a/core/src/main/java/io/neba/core/resourcemodels/factory/ClassBasedModelDefinition.java b/core/src/main/java/io/neba/core/resourcemodels/factory/ClassBasedModelDefinition.java index a7fc1e73..12edde8d 100644 --- a/core/src/main/java/io/neba/core/resourcemodels/factory/ClassBasedModelDefinition.java +++ b/core/src/main/java/io/neba/core/resourcemodels/factory/ClassBasedModelDefinition.java @@ -20,6 +20,7 @@ import javax.annotation.Nonnull; +import static io.neba.core.util.Annotations.annotations; import static java.lang.Character.toLowerCase; /** @@ -35,7 +36,7 @@ class ClassBasedModelDefinition implements ModelDefinition { @Nonnull @Override public ResourceModel getResourceModel() { - return c.getAnnotation(ResourceModel.class); + return annotations(c).get(ResourceModel.class); } @Nonnull diff --git a/core/src/main/java/io/neba/core/resourcemodels/factory/ModelFactory.java b/core/src/main/java/io/neba/core/resourcemodels/factory/ModelFactory.java index 83290c4e..9ac2d0c0 100644 --- a/core/src/main/java/io/neba/core/resourcemodels/factory/ModelFactory.java +++ b/core/src/main/java/io/neba/core/resourcemodels/factory/ModelFactory.java @@ -22,21 +22,14 @@ import javax.annotation.Nonnull; import java.net.URL; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; +import java.util.*; import java.util.stream.Stream; +import static io.neba.core.util.Annotations.annotations; import static java.util.Arrays.stream; import static java.util.Collections.emptyList; import static java.util.Collections.unmodifiableList; -import static java.util.Optional.empty; -import static java.util.Optional.of; -import static java.util.Optional.ofNullable; +import static java.util.Optional.*; import static java.util.stream.Collectors.toList; /** @@ -46,9 +39,10 @@ * the models, including injection of OSGi service dependencies via {@link javax.inject.Inject} and {@link io.neba.api.annotations.Filter}. */ class ModelFactory implements ResourceModelFactory { + private static final String SPRING_COMPONENT_STEREOTYPE = "org.springframework.stereotype.Component"; private final Bundle bundle; - private List> modelDefinitions; - private Map, ModelInstantiator> modelMetadata; + private final List> modelDefinitions; + private final Map, ModelInstantiator> modelMetadata; ModelFactory(Bundle bundle) { this.bundle = bundle; @@ -66,8 +60,10 @@ class ModelFactory implements ResourceModelFactory { .flatMap(this::streamUrls) .map(this::urlToClassName) .map(this::loadClass) - .filter(o -> o.map(c -> c.isAnnotationPresent(ResourceModel.class)).orElse(false)) + .filter(Optional::isPresent) .map(Optional::get) + .filter(c -> annotations(c).contains(ResourceModel.class)) + .filter(c -> !annotations(c).containsName(SPRING_COMPONENT_STEREOTYPE)) .map(ClassBasedModelDefinition::new) .distinct() .collect(toList())); diff --git a/core/src/test/java/io/neba/core/resourcemodels/factory/ModelFactoryTest.java b/core/src/test/java/io/neba/core/resourcemodels/factory/ModelFactoryTest.java index 94c67c60..64087f64 100644 --- a/core/src/test/java/io/neba/core/resourcemodels/factory/ModelFactoryTest.java +++ b/core/src/test/java/io/neba/core/resourcemodels/factory/ModelFactoryTest.java @@ -25,17 +25,22 @@ import org.mockito.junit.MockitoJUnitRunner; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; +import org.springframework.stereotype.Component; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.net.MalformedURLException; import java.net.URL; import java.util.Dictionary; import java.util.Hashtable; +import java.util.List; import java.util.Vector; +import static java.util.Arrays.asList; +import static java.util.stream.Collectors.toList; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.*; /** * @author Olaf Otto @@ -61,32 +66,46 @@ public void setUp() throws Exception { doReturn(this.bundleContext).when(this.bundle).getBundleContext(); - // The actual protocol for OSGi bundles is "bundleresource:", but this protocol is not registered for unit tests. - URL modelClassResource = new URL("file://bundleId.bundleVersion" + "/" + ModelClass.class.getName().replace('.', '/') + ".class"); - URL nonModelClassResource = new URL("file://bundleId.bundleVersion" + "/" + NonModelClass.class.getName().replace('.', '/') + ".class"); + List> modelTypes = asList(ModelClass.class, ModelClassWithMetaAnnotation.class, NonModelClass.class, SpringModelClass.class, SpringModelClassWithMetaAnnotation.class); - Vector vector = new Vector<>(); - vector.add(modelClassResource); - vector.add(nonModelClassResource); + Vector vector = modelTypes.stream() + // The actual protocol for OSGi bundles is "bundleresource:", but this protocol is not registered for unit tests. + .map(cls -> "file://bundleId.bundleVersion" + "/" + cls.getName().replace('.', '/') + ".class") + .map(ModelFactoryTest::toUrl).collect(java.util.stream.Collectors.toCollection(Vector::new)); doReturn(vector.elements()).when(this.bundle).findEntries("/first/package", "*.class", true); - doReturn(ModelClass.class).when(this.bundle).loadClass(ModelClass.class.getName()); - doReturn(NonModelClass.class).when(this.bundle).loadClass(NonModelClass.class.getName()); + modelTypes.forEach(cls -> { + try { + doReturn(cls).when(this.bundle).loadClass(cls.getName()); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + }); + doAnswer(inv -> inv.getArguments()[0]).when(callback).map(any()); this.testee = new ModelFactory(this.bundle); } @Test + @SuppressWarnings("rawtypes") public void testModelFactoryFindsResourceModel() { assertThat(this.testee.getModelDefinitions()) - .hasSize(1); - assertThat(this.testee.getModelDefinitions().iterator().next().getType()) - .isSameAs(ModelClass.class); - assertThat(this.testee.getModelDefinitions().iterator().next().getName()) - .isEqualTo("modelClass"); - assertThat(this.testee.getModelDefinitions().iterator().next().getResourceModel()) - .isSameAs(ModelClass.class.getAnnotation(ResourceModel.class)); + .hasSize(2); + + assertThat(this.testee.getModelDefinitions()) + .extracting(def -> (Class) def.getType()) + .containsExactly(ModelClass.class, ModelClassWithMetaAnnotation.class); + + assertThat(this.testee.getModelDefinitions()) + .extracting(ModelDefinition::getName) + .containsExactly("modelClass", "modelClassWithMetaAnnotation"); + + assertThat(this.testee.getModelDefinitions()).extracting(ModelDefinition::getResourceModel) + .containsExactly( + ModelClass.class.getAnnotation(ResourceModel.class), + ModelClassWithMetaAnnotation.class.getAnnotation(CustomModelStereotype.class).annotationType().getAnnotation(ResourceModel.class) + ); } @Test @@ -108,10 +127,58 @@ public void testModelDefinitionsAreUnmodifiable() { this.testee.getModelDefinitions().add(mock(ModelDefinition.class)); } + @Test + public void testSpringModelsAreExcluded() { + assertDetectedModelsDoesNotInclude(SpringModelClass.class); + } + + private void assertDetectedModelsDoesNotInclude(Class modelType) { + List> detectedTypes = + this.testee.getModelDefinitions() + .stream() + .map(ModelDefinition::getType) + .collect(toList()); + + assertThat(detectedTypes).doesNotContain(modelType); + } + @ResourceModel("some/type") public static class ModelClass { } + @CustomModelStereotype + public static class ModelClassWithMetaAnnotation { + } + public static class NonModelClass { } + + @Component + @ResourceModel("some/type") + public static class SpringModelClass { + } + + @CustomSpringModelStereotype + @ResourceModel("some/type") + public static class SpringModelClassWithMetaAnnotation { + } + + @ResourceModel("some/type") + @Retention(RetentionPolicy.RUNTIME) + public @interface CustomModelStereotype { + + } + + @Component + @Retention(RetentionPolicy.RUNTIME) + public @interface CustomSpringModelStereotype { + } + + private static URL toUrl(String s) { + try { + return new URL(s); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } } diff --git a/core/src/test/java/org/springframework/stereotype/Component.java b/core/src/test/java/org/springframework/stereotype/Component.java new file mode 100644 index 00000000..2537c065 --- /dev/null +++ b/core/src/test/java/org/springframework/stereotype/Component.java @@ -0,0 +1,31 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.stereotype; + +import java.lang.annotation.*; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface Component { + + /** + * The value may indicate a suggestion for a logical component name, + * to be turned into a Spring bean in case of an autodetected component. + * @return the suggested component name, if any (or empty String otherwise) + */ + String value() default ""; +}