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;
+}