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 2021/12/04 13:28:30 UTC
[sling-org-apache-sling-models-impl] branch master updated: SLING-8069: allow non-public constructors (#11)
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 d56cf5f SLING-8069: allow non-public constructors (#11)
d56cf5f is described below
commit d56cf5f3013c2095b876c408510c29ec71ea3b05
Author: paul-bjorkstrand <pa...@perficient.com>
AuthorDate: Sat Dec 4 07:28:24 2021 -0600
SLING-8069: allow non-public constructors (#11)
---
.../sling/models/impl/ModelAdapterFactory.java | 13 ++---
.../apache/sling/models/impl/model/ModelClass.java | 12 ++--
.../models/impl/model/ModelClassConstructor.java | 46 +++++++++++++--
.../models/impl/ConstructorVisibilityTest.java | 65 ++++++++++++++++++++++
.../PackagePrivateConstructorModel.java | 31 +++++++++++
.../PrivateConstructorModel.java | 31 +++++++++++
.../ProtectedConstructorModel.java | 31 +++++++++++
7 files changed, 208 insertions(+), 21 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 4cfb367..569671c 100644
--- a/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
+++ b/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java
@@ -695,7 +695,8 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable, ModelFacto
ModelType object;
if (constructorToUse.getConstructor().getParameterTypes().length == 0) {
// no parameters for constructor injection? instantiate it right away
- object = constructorToUse.getConstructor().newInstance();
+
+ object = constructorToUse.newInstance();
} else {
// instantiate with constructor injection
// if this fails, make sure resources that may be claimed by injectors are cleared up again
@@ -707,13 +708,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable, ModelFacto
} else {
object = result.getValue();
}
- } catch (InstantiationException ex) {
- registry.onDisposed();
- throw ex;
- } catch (InvocationTargetException ex) {
- registry.onDisposed();
- throw ex;
- } catch (IllegalAccessException ex) {
+ } catch (InstantiationException | InvocationTargetException | IllegalAccessException ex) {
registry.onDisposed();
throw ex;
}
@@ -820,7 +815,7 @@ public class ModelAdapterFactory implements AdapterFactory, Runnable, ModelFacto
}
return new Result<>(missingElementsException);
}
- return new Result<>(constructor.getConstructor().newInstance(paramValues.toArray(new Object[paramValues.size()])));
+ return new Result<>(constructor.newInstance(paramValues.toArray(new Object[paramValues.size()])));
}
private Result<Boolean> injectDefaultValue(InjectableElement point, InjectAnnotationProcessor processor,
diff --git a/src/main/java/org/apache/sling/models/impl/model/ModelClass.java b/src/main/java/org/apache/sling/models/impl/model/ModelClass.java
index 6c17e47..4f81a62 100644
--- a/src/main/java/org/apache/sling/models/impl/model/ModelClass.java
+++ b/src/main/java/org/apache/sling/models/impl/model/ModelClass.java
@@ -34,7 +34,7 @@ public class ModelClass<ModelType> {
private final Class<ModelType> type;
private final Model modelAnnotation;
final DefaultInjectionStrategy defaultInjectionStrategy;
- private volatile ModelClassConstructor<?>[] constructors;
+ private volatile ModelClassConstructor<ModelType>[] constructors;
private volatile InjectableField[] injectableFields;
private volatile InjectableMethod[] injectableMethods;
@@ -60,18 +60,18 @@ public class ModelClass<ModelType> {
}
@SuppressWarnings("unchecked")
- private static ModelClassConstructor<?>[] getConstructors(Class<?> type, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
+ private static <T> ModelClassConstructor<T>[] getConstructors(Class<T> type, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
if (type.isInterface()) {
return new ModelClassConstructor[0];
}
- Constructor<?>[] constructors = type.getConstructors();
+ Constructor<T>[] constructors = (Constructor<T>[]) type.getDeclaredConstructors();
// sort the constructor list in order from most params to least params, and constructors with @Inject annotation first
Arrays.sort(constructors, new ParameterCountInjectComparator());
- ModelClassConstructor<?>[] array = new ModelClassConstructor[constructors.length];
+ ModelClassConstructor<T>[] array = new ModelClassConstructor[constructors.length];
for (int i=0; i<array.length; i++) {
- array[i] = new ModelClassConstructor(constructors[i], processorFactories, defaultInjectionStrategy);
+ array[i] = new ModelClassConstructor<>(constructors[i], processorFactories, defaultInjectionStrategy);
}
return array;
}
@@ -112,7 +112,7 @@ public class ModelClass<ModelType> {
return this.modelAnnotation != null;
}
- public ModelClassConstructor[] getConstructors() {
+ public ModelClassConstructor<ModelType>[] getConstructors() {
return constructors;
}
diff --git a/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java b/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java
index 4e9a047..5629839 100644
--- a/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java
+++ b/src/main/java/org/apache/sling/models/impl/model/ModelClassConstructor.java
@@ -19,6 +19,7 @@
package org.apache.sling.models.impl.model;
import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Type;
import javax.inject.Inject;
@@ -27,13 +28,13 @@ import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.impl.ReflectionUtil;
import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory;
-public class ModelClassConstructor<ModelType> {
+public class ModelClassConstructor<M> {
- private final Constructor<ModelType> constructor;
+ private final Constructor<M> constructor;
private final boolean hasInjectAnnotation;
private final ConstructorParameter[] constructorParametersArray;
- public ModelClassConstructor(Constructor<ModelType> constructor, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
+ public ModelClassConstructor(Constructor<M> constructor, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
this.constructor = constructor;
this.hasInjectAnnotation = constructor.isAnnotationPresent(Inject.class);
@@ -49,10 +50,43 @@ public class ModelClassConstructor<ModelType> {
}
}
- public Constructor<ModelType> getConstructor() {
+ /**
+ * Proxies the call to {@link Constructor#newInstance(Object...)}, checking (and
+ * setting) accessibility first.
+ *
+ * @param parameters
+ * the constructor parameters that are passed to
+ * {@link Constructor#newInstance(Object...)}
+ * @return The constructed object
+ *
+ * @throws InstantiationException when {@link Constructor#newInstance(Object...)} would throw
+ * @throws IllegalAccessException when {@link Constructor#newInstance(Object...)} would throw
+ * @throws IllegalArgumentException when {@link Constructor#newInstance(Object...)} would throw
+ * @throws InvocationTargetException when {@link Constructor#newInstance(Object...)} would throw
+ *
+ * @see Constructor#newInstance(Object...)
+ */
+ @SuppressWarnings({"java:S3011","java:S1874"})
+ public M newInstance(Object... parameters) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+ synchronized (constructor) {
+ boolean accessible = constructor.isAccessible();
+ try {
+ if (!accessible) {
+ constructor.setAccessible(true);
+ }
+ return constructor.newInstance(parameters);
+ } finally {
+ if (!accessible) {
+ constructor.setAccessible(false);
+ }
+ }
+ }
+ }
+
+ public Constructor<M> getConstructor() {
return constructor;
}
-
+
public boolean hasInjectAnnotation() {
return hasInjectAnnotation;
}
@@ -60,5 +94,5 @@ public class ModelClassConstructor<ModelType> {
public ConstructorParameter[] getConstructorParameters() {
return constructorParametersArray;
};
-
+
}
diff --git a/src/test/java/org/apache/sling/models/impl/ConstructorVisibilityTest.java b/src/test/java/org/apache/sling/models/impl/ConstructorVisibilityTest.java
new file mode 100644
index 0000000..b1c449f
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/impl/ConstructorVisibilityTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.assertNotNull;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.impl.injectors.RequestAttributeInjector;
+import org.apache.sling.models.impl.injectors.SelfInjector;
+import org.apache.sling.models.testmodels.classes.constructorvisibility.PackagePrivateConstructorModel;
+import org.apache.sling.models.testmodels.classes.constructorvisibility.PrivateConstructorModel;
+import org.apache.sling.models.testmodels.classes.constructorvisibility.ProtectedConstructorModel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+
+@RunWith(MockitoJUnitRunner.class)
+public class ConstructorVisibilityTest {
+ private ModelAdapterFactory factory;
+
+ @Mock
+ private SlingHttpServletRequest request;
+
+ @Before
+ public void setup() {
+ factory = AdapterFactoryTest.createModelAdapterFactory();
+ factory.bindInjector(new RequestAttributeInjector(), new ServicePropertiesMap(1, 1));
+ factory.bindInjector(new SelfInjector(), new ServicePropertiesMap(2, 2));
+ factory.adapterImplementations.addClassesAsAdapterAndImplementation(ProtectedConstructorModel.class, PackagePrivateConstructorModel.class, PrivateConstructorModel.class);
+ }
+
+ @Test
+ public void testNonPublicConstructorProtectedModel() {
+ ProtectedConstructorModel model = factory.createModel(request, ProtectedConstructorModel.class);
+ assertNotNull(model);
+ }
+
+ @Test
+ public void testNonPublicConstructorPackagePrivateModel() {
+ PackagePrivateConstructorModel model = factory.createModel(request, PackagePrivateConstructorModel.class);
+ assertNotNull(model);
+ }
+
+ @Test
+ public void testNonPublicConstructorPrivateModel() {
+ PrivateConstructorModel model = factory.createModel(request, PrivateConstructorModel.class);
+ assertNotNull(model);
+ }
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/PackagePrivateConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/PackagePrivateConstructorModel.java
new file mode 100644
index 0000000..cb3cdba
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/PackagePrivateConstructorModel.java
@@ -0,0 +1,31 @@
+/*
+ * 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.constructorvisibility;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class PackagePrivateConstructorModel {
+
+ @Inject
+ PackagePrivateConstructorModel() {
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/PrivateConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/PrivateConstructorModel.java
new file mode 100644
index 0000000..85eef0d
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/PrivateConstructorModel.java
@@ -0,0 +1,31 @@
+/*
+ * 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.constructorvisibility;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class PrivateConstructorModel {
+
+ @Inject
+ private PrivateConstructorModel() {
+ }
+
+}
diff --git a/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/ProtectedConstructorModel.java b/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/ProtectedConstructorModel.java
new file mode 100644
index 0000000..aa3f2de
--- /dev/null
+++ b/src/test/java/org/apache/sling/models/testmodels/classes/constructorvisibility/ProtectedConstructorModel.java
@@ -0,0 +1,31 @@
+/*
+ * 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.constructorvisibility;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.models.annotations.Model;
+
+@Model(adaptables = SlingHttpServletRequest.class)
+public class ProtectedConstructorModel {
+
+ @Inject
+ protected ProtectedConstructorModel() {
+ }
+
+}