blob: 6c17e47b1bd10a1e5574bf1c5b8528cccd80a9b9 [file] [log] [blame]
/*
* 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.model;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import org.apache.sling.models.annotations.DefaultInjectionStrategy;
import org.apache.sling.models.annotations.Model;
import org.apache.sling.models.impl.ReflectionUtil;
import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory;
public class ModelClass<ModelType> {
private final Class<ModelType> type;
private final Model modelAnnotation;
final DefaultInjectionStrategy defaultInjectionStrategy;
private volatile ModelClassConstructor<?>[] constructors;
private volatile InjectableField[] injectableFields;
private volatile InjectableMethod[] injectableMethods;
public ModelClass(Class<ModelType> type, StaticInjectAnnotationProcessorFactory[] processorFactories) {
this.type = type;
this.modelAnnotation = type.getAnnotation(Model.class);
if (modelAnnotation == null) {
defaultInjectionStrategy = DefaultInjectionStrategy.REQUIRED;
} else {
defaultInjectionStrategy = modelAnnotation.defaultInjectionStrategy();
}
updateProcessorFactories(processorFactories);
}
/**
* Updates processor factories after the model class was instantiated.
* @param processorFactories Static injector annotation processor factories
*/
public void updateProcessorFactories(StaticInjectAnnotationProcessorFactory[] processorFactories) {
this.constructors = getConstructors(type, processorFactories, defaultInjectionStrategy);
this.injectableFields = getInjectableFields(type, processorFactories, defaultInjectionStrategy);
this.injectableMethods = getInjectableMethods(type, processorFactories, defaultInjectionStrategy);
}
@SuppressWarnings("unchecked")
private static ModelClassConstructor<?>[] getConstructors(Class<?> type, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
if (type.isInterface()) {
return new ModelClassConstructor[0];
}
Constructor<?>[] constructors = type.getConstructors();
// 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];
for (int i=0; i<array.length; i++) {
array[i] = new ModelClassConstructor(constructors[i], processorFactories, defaultInjectionStrategy);
}
return array;
}
private static InjectableField[] getInjectableFields(Class<?> type, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
if (type.isInterface()) {
return new InjectableField[0];
}
List<Field> injectableFields = ReflectionUtil.collectInjectableFields(type);
InjectableField[] array = new InjectableField[injectableFields.size()];
for (int i=0; i<array.length; i++) {
array[i] = new InjectableField(injectableFields.get(i), processorFactories, defaultInjectionStrategy);
}
return array;
}
private static InjectableMethod[] getInjectableMethods(Class<?> type, StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) {
if (!type.isInterface()) {
return new InjectableMethod[0];
}
List<Method> injectableMethods = ReflectionUtil.collectInjectableMethods(type);
InjectableMethod[] array = new InjectableMethod[injectableMethods.size()];
for (int i=0; i<array.length; i++) {
array[i] = new InjectableMethod(injectableMethods.get(i), processorFactories, defaultInjectionStrategy);
}
return array;
}
public Class<ModelType> getType() {
return this.type;
}
public Model getModelAnnotation() {
return this.modelAnnotation;
}
public boolean hasModelAnnotation() {
return this.modelAnnotation != null;
}
public ModelClassConstructor[] getConstructors() {
return constructors;
}
public InjectableField[] getInjectableFields() {
return this.injectableFields;
}
public InjectableMethod[] getInjectableMethods() {
return this.injectableMethods;
}
}