/* * 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; } }