You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2020/10/01 06:34:16 UTC
[sling-org-apache-sling-models-impl] branch master updated:
SLING-9755 make annotation parsing more lenient (#19)
This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git
The following commit(s) were added to refs/heads/master by this push:
new ddf8f2d SLING-9755 make annotation parsing more lenient (#19)
ddf8f2d is described below
commit ddf8f2d7c32da2bf9196e798f5e59f69b962739c
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Thu Oct 1 08:34:10 2020 +0200
SLING-9755 make annotation parsing more lenient (#19)
also catch AnnotationFormatError in
ModelBundleListener.analyzeClass(...)
add tests for ModelPackageBundleListener
---
pom.xml | 6 ++
.../models/impl/ModelPackageBundleListener.java | 5 +-
.../impl/ModelPackageBundleListenerTest.java | 112 +++++++++++++++++++++
.../SimpleModelWithInvalidSecondAnnotation.java | 27 +++++
.../testmodels/classes/annotations/Hidden.java | 21 ++++
.../classes/annotations/OtherAnnotation.java | 29 ++++++
6 files changed, 198 insertions(+), 2 deletions(-)
diff --git a/pom.xml b/pom.xml
index 7aef7a3..8e19fc4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -216,5 +216,11 @@
<version>1.0.8</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <version>5.2.9.RELEASE</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
index c3b1757..8928d46 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelPackageBundleListener.java
@@ -16,6 +16,7 @@
*/
package org.apache.sling.models.impl;
+import java.lang.annotation.AnnotationFormatError;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
@@ -187,8 +188,8 @@ public class ModelPackageBundleListener implements BundleTrackerCustomizer<Servi
}
}
- } catch (ClassNotFoundException e) {
- log.warn("Unable to load class", e);
+ } catch (ClassNotFoundException|AnnotationFormatError e) {
+ log.warn("Unable to load class '{}' from bundle '{}': {}", className, bundle.getSymbolicName(), e.getLocalizedMessage(), e);
}
}
diff --git a/src/test/java/org/apache/sling/models/impl/ModelPackageBundleListenerTest.java b/src/test/java/org/apache/sling/models/impl/ModelPackageBundleListenerTest.java
new file mode 100644
index 0000000..baa2684
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ModelPackageBundleListenerTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.apache.sling.models.impl;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.sling.models.testmodels.classes.ChildModel;
+import org.apache.sling.models.testmodels.classes.SimpleModelWithInvalidSecondAnnotation;
+import org.apache.sling.models.testmodels.classes.annotations.Hidden;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.mockito.stubbing.Answer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.springframework.core.OverridingClassLoader;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ModelPackageBundleListenerTest {
+
+ @Mock
+ private BundleContext mockBundleContext;
+
+ @Mock
+ private ModelAdapterFactory mockModelAdapterFactory;
+
+ @Mock
+ private Bundle mockBundle;
+
+ final AdapterImplementations adapterImplementations = new AdapterImplementations();
+
+ /**
+ * ClassLoader which doesn't delegate to the parent. In addition it blocks loading certain classes.
+ */
+ private static final class HideClassesClassLoader extends OverridingClassLoader {
+
+ private final Collection<String> classNamesToHide;
+ public HideClassesClassLoader(ClassLoader parent, String... classNamesToHide) {
+ super(parent);
+ this.classNamesToHide = Arrays.asList(classNamesToHide);
+ }
+
+ @Override
+ protected Class<?> loadClassForOverriding(String name) throws ClassNotFoundException {
+ if (classNamesToHide.contains(name)) {
+ throw new ClassNotFoundException("Could not find class " + name + " as it is hidden by this class loader!");
+ }
+ return super.loadClassForOverriding(name);
+ }
+ }
+
+ @Test
+ public void testAddingBundleWithResolvableModelAnnotation() throws ClassNotFoundException {
+ Assert.assertFalse("Model should not yet have been registered but was", adapterImplementations.isModelClass(ChildModel.class));
+ ModelPackageBundleListener listener = createListenerForBundleWithClass(ChildModel.class);
+ listener.addingBundle(mockBundle, new BundleEvent(BundleEvent.STARTED, mockBundle));
+ Assert.assertTrue("Model should have been registered but was not", adapterImplementations.isModelClass(ChildModel.class));
+ }
+
+ @Test
+ public void testAddingBundleWithNonResolvableNonModelAnnotation() throws ClassNotFoundException {
+ ClassLoader classLoader = new HideClassesClassLoader(this.getClass().getClassLoader(), Hidden.class.getName());
+ ModelPackageBundleListener listener = createListenerForBundleWithClass(classLoader, SimpleModelWithInvalidSecondAnnotation.class.getName());
+ listener.addingBundle(mockBundle, new BundleEvent(BundleEvent.STARTED, mockBundle));
+ Assert.assertFalse("Model should not yet have been registered but was", adapterImplementations.isModelClass(SimpleModelWithInvalidSecondAnnotation.class));
+ }
+
+ private ModelPackageBundleListener createListenerForBundleWithClass(Class<?> modelClass) throws ClassNotFoundException {
+ return createListenerForBundleWithClass(modelClass.getClassLoader(), modelClass.getName());
+ }
+
+ private ModelPackageBundleListener createListenerForBundleWithClass(ClassLoader classLoader, String className) throws ClassNotFoundException {
+ Dictionary<String, String> headers = new Hashtable<>();
+ headers.put(ModelPackageBundleListener.CLASSES_HEADER, className);
+ Mockito.when(mockBundle.getHeaders()).thenReturn(headers);
+ Mockito.when(mockBundle.loadClass(Mockito.anyString())).thenAnswer(new Answer<Class<?>>(){
+ @Override
+ public Class<?>answer(InvocationOnMock invocation) throws Throwable {
+ Object argument = invocation.getArguments()[0];
+ if (argument.equals(className)) {
+ return classLoader.loadClass(className);
+ } else {
+ throw new ClassNotFoundException("Could not find class with name " + argument);
+ }
+ }
+ });
+ return new ModelPackageBundleListener(mockBundleContext, mockModelAdapterFactory, adapterImplementations, null, null);
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SimpleModelWithInvalidSecondAnnotation.java b/src/test/java/org/apache/sling/models/testmodels/classes/SimpleModelWithInvalidSecondAnnotation.java
new file mode 100644
index 0000000..03f7be1
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SimpleModelWithInvalidSecondAnnotation.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.apache.sling.models.testmodels.classes;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Model;
+import org.apache.sling.models.testmodels.classes.annotations.OtherAnnotation;
+
+@Model(adaptables = Resource.class)
+@OtherAnnotation()
+public class SimpleModelWithInvalidSecondAnnotation {
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/annotations/Hidden.java b/src/test/java/org/apache/sling/models/testmodels/classes/annotations/Hidden.java
new file mode 100644
index 0000000..0b09f8a
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/annotations/Hidden.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.apache.sling.models.testmodels.classes.annotations;
+
+public class Hidden {
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/annotations/OtherAnnotation.java b/src/test/java/org/apache/sling/models/testmodels/classes/annotations/OtherAnnotation.java
new file mode 100644
index 0000000..52e7c6e
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/annotations/OtherAnnotation.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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
+ *
+ * http://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.apache.sling.models.testmodels.classes.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface OtherAnnotation {
+
+ Class<?> someClass() default Hidden.class;
+}