You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:54:48 UTC

[sling-org-apache-sling-models-impl] 06/10: SLING-3357 - allow a model class to have a single argument constructor which takes the adaptable as a parameter.

This is an automated email from the ASF dual-hosted git repository.

rombert pushed a commit to annotated tag org.apache.sling.models.impl-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-models-impl.git

commit e9a5ebd8f6acc142a2849c6d1f58c605b2d38731
Author: Justin Edelson <ju...@apache.org>
AuthorDate: Fri Jan 31 04:07:05 2014 +0000

    SLING-3357 - allow a model class to have a single argument constructor which takes the adaptable as a parameter.
    
    git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/models/impl@1563049 13f79535-47bb-0310-9956-ffa450edef68
---
 .../sling/models/impl/ModelAdapterFactory.java     |  61 +++++++++++-
 .../apache/sling/models/impl/ConstructorTest.java  | 104 +++++++++++++++++++++
 .../classes/InvalidConstructorModel.java           |  44 +++++++++
 .../classes/SuperclassConstructorModel.java        |  47 ++++++++++
 .../classes/WithOneConstructorModel.java           |  43 +++++++++
 .../classes/WithThreeConstructorsModel.java        |  58 ++++++++++++
 .../classes/WithTwoConstructorsModel.java          |  46 +++++++++
 7 files changed, 401 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
index 92fc791..7d29234 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -20,13 +20,17 @@ import java.lang.annotation.Annotation;
 import java.lang.ref.PhantomReference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
 import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -70,6 +74,19 @@ import org.slf4j.LoggerFactory;
 @Component
 public class ModelAdapterFactory implements AdapterFactory, Runnable {
 
+    /**
+     * Comparator which sorts constructors by the number of parameters
+     * in reverse order (most params to least params).
+     */
+    public class ParameterCountComparator implements Comparator<Constructor<?>> {
+
+        @Override
+        public int compare(Constructor<?> o1, Constructor<?> o2) {
+            return Integer.compare(o2.getParameterTypes().length, o1.getParameterTypes().length);
+        }
+
+    }
+
     private static class DisposalCallbackRegistryImpl implements DisposalCallbackRegistry {
 
         private List<DisposalCallback> callbacks = new ArrayList<DisposalCallback>();
@@ -282,11 +299,51 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable {
         return null;
     }
 
+    @SuppressWarnings("unchecked")
     private <AdapterType> AdapterType createObject(Object adaptable, Class<AdapterType> type)
-            throws InstantiationException, IllegalAccessException {
+            throws InstantiationException, InvocationTargetException, IllegalAccessException {
         Set<Field> injectableFields = collectInjectableFields(type);
 
-        AdapterType object = type.newInstance();
+        Constructor<?>[] constructors = type.getConstructors();
+        if (constructors.length == 0) {
+            log.warn("Model class {} does not have a public constructor.", type.getName());
+            return null;
+        }
+
+        // sort the constructor list in order from most params to least params
+        Arrays.sort(constructors, new ParameterCountComparator());
+
+        Constructor<AdapterType> constructorToUse = null;
+        boolean constructorHasParam = false;
+        for (Constructor<?> constructor : constructors) {
+            final Class<?>[] paramTypes = constructor.getParameterTypes();
+            if (paramTypes.length == 1) {
+                Class<?> paramType = constructor.getParameterTypes()[0];
+                if (paramType.isInstance(adaptable)) {
+                    constructorToUse = (Constructor<AdapterType>) constructor;
+                    constructorHasParam = true;
+                    break;
+                }
+            }
+
+            if (constructor.getParameterTypes().length == 0) {
+                constructorToUse = (Constructor<AdapterType>) constructor;
+                constructorHasParam = false;
+                break;
+            }
+        }
+
+        if (constructorToUse == null) {
+            log.warn("Model class {} does not have a usable constructor", type.getName());
+            return null;
+        }
+
+        final AdapterType object;
+        if (constructorHasParam) {
+            object = constructorToUse.newInstance(adaptable);
+        } else {
+            object = constructorToUse.newInstance();
+        }
 
         DisposalCallbackRegistryImpl registry = createAndRegisterCallbackRegistry(object);
 
diff --git a/src/test/java/org/apache/sling/models/impl/ConstructorTest.java b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
new file mode 100644
index 0000000..130818d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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 static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import java.util.Collections;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+import org.apache.sling.models.testmodels.classes.InvalidConstructorModel;
+import org.apache.sling.models.testmodels.classes.SuperclassConstructorModel;
+import org.apache.sling.models.testmodels.classes.WithOneConstructorModel;
+import org.apache.sling.models.testmodels.classes.WithThreeConstructorsModel;
+import org.apache.sling.models.testmodels.classes.WithTwoConstructorsModel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.component.ComponentContext;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ConstructorTest {
+
+    @Mock
+    private ComponentContext componentCtx;
+
+    @Mock
+    private BundleContext bundleContext;
+
+    private ModelAdapterFactory factory;
+
+    @Mock
+    private SlingHttpServletRequest request;
+
+    @Before
+    public void setup() {
+        when(componentCtx.getBundleContext()).thenReturn(bundleContext);
+
+        when(request.getAttribute("attribute")).thenReturn(42);
+
+        factory = new ModelAdapterFactory();
+        factory.activate(componentCtx);
+        factory.bindInjector(new RequestAttributeInjector(),
+                Collections.<String, Object> singletonMap(Constants.SERVICE_ID, 0L));
+    }
+
+    @Test
+    public void testConstructorInjection() {
+        WithOneConstructorModel model = factory.getAdapter(request, WithOneConstructorModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testThreeConstructorsInjection() {
+        WithThreeConstructorsModel model = factory.getAdapter(request, WithThreeConstructorsModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testTwoConstructorsInjection() {
+        WithTwoConstructorsModel model = factory.getAdapter(request, WithTwoConstructorsModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testSuperclassConstructorsInjection() {
+        SuperclassConstructorModel model = factory.getAdapter(request, SuperclassConstructorModel.class);
+        assertNotNull(model);
+        assertEquals(request, model.getRequest());
+        assertEquals(42, model.getAttribute());
+    }
+
+    @Test
+    public void testInvalidConstructorInjector() {
+        InvalidConstructorModel model = factory.getAdapter(request, InvalidConstructorModel.class);
+        assertNull(model);
+    }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java
new file mode 100644
index 0000000..bf032b6
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java
@@ -0,0 +1,44 @@
+/*
+ * 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 javax.inject.Inject;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class InvalidConstructorModel {
+
+    private HttpServletResponse response;
+
+    @Inject
+    private int attribute;
+
+    public InvalidConstructorModel(HttpServletResponse response) {
+        this.response = response;
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public HttpServletResponse getResponse() {
+        return response;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java
new file mode 100644
index 0000000..c764fc7
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java
@@ -0,0 +1,47 @@
+/*
+ * 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 javax.inject.Inject;
+import javax.servlet.http.HttpServletRequest;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class SuperclassConstructorModel {
+
+    private HttpServletRequest request;
+
+    @Inject
+    private int attribute;
+
+    public SuperclassConstructorModel(HttpServletRequest request) {
+        this.request = request;
+    }
+
+    public SuperclassConstructorModel() {
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public HttpServletRequest getRequest() {
+        return request;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java
new file mode 100644
index 0000000..c16b980
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java
@@ -0,0 +1,43 @@
+/*
+ * 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 javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class WithOneConstructorModel {
+
+    private final SlingHttpServletRequest request;
+
+    @Inject
+    private int attribute;
+
+    public WithOneConstructorModel(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java
new file mode 100644
index 0000000..d701341
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java
@@ -0,0 +1,58 @@
+/*
+ * 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 javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class WithThreeConstructorsModel {
+
+    private SlingHttpServletRequest request;
+    
+    private SlingHttpServletResponse response;
+
+    @Inject
+    private int attribute;
+
+    public WithThreeConstructorsModel(SlingHttpServletRequest request, SlingHttpServletResponse response) {
+        this.request = request;
+        this.response = response;
+    }
+
+    public WithThreeConstructorsModel(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public WithThreeConstructorsModel() {
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+    
+    public SlingHttpServletResponse getResponse() {
+        return response;
+    }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java
new file mode 100644
index 0000000..edadf24
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java
@@ -0,0 +1,46 @@
+/*
+ * 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 javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class WithTwoConstructorsModel {
+
+    private SlingHttpServletRequest request;
+
+    @Inject
+    private int attribute;
+
+    public WithTwoConstructorsModel(SlingHttpServletRequest request) {
+        this.request = request;
+    }
+
+    public WithTwoConstructorsModel() {
+    }
+
+    public int getAttribute() {
+        return attribute;
+    }
+
+    public SlingHttpServletRequest getRequest() {
+        return request;
+    }
+}

-- 
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.