You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ju...@apache.org on 2014/01/31 05:07:06 UTC
svn commit: r1563049 - in /sling/trunk/bundles/extensions/models/impl/src:
main/java/org/apache/sling/models/impl/
test/java/org/apache/sling/models/impl/
test/java/org/apache/sling/models/testmodels/classes/
Author: justin
Date: Fri Jan 31 04:07:05 2014
New Revision: 1563049
URL: http://svn.apache.org/r1563049
Log:
SLING-3357 - allow a model class to have a single argument constructor which takes the adaptable as a parameter.
Added:
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java
sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java
Modified:
sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java?rev=1563049&r1=1563048&r2=1563049&view=diff
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java (original)
+++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java Fri Jan 31 04:07:05 2014
@@ -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 impleme
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);
Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java?rev=1563049&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ConstructorTest.java Fri Jan 31 04:07:05 2014
@@ -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);
+ }
+
+}
Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java?rev=1563049&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/InvalidConstructorModel.java Fri Jan 31 04:07:05 2014
@@ -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;
+ }
+}
Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java?rev=1563049&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/SuperclassConstructorModel.java Fri Jan 31 04:07:05 2014
@@ -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;
+ }
+}
Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java?rev=1563049&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithOneConstructorModel.java Fri Jan 31 04:07:05 2014
@@ -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;
+ }
+}
Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java?rev=1563049&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithThreeConstructorsModel.java Fri Jan 31 04:07:05 2014
@@ -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;
+ }
+}
Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java?rev=1563049&view=auto
==============================================================================
--- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java (added)
+++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/WithTwoConstructorsModel.java Fri Jan 31 04:07:05 2014
@@ -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;
+ }
+}