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>.