| /* |
| * 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.AnnotatedElement; |
| import java.lang.reflect.Type; |
| |
| import javax.inject.Named; |
| |
| import org.apache.commons.lang3.ArrayUtils; |
| import org.apache.sling.models.annotations.Default; |
| import org.apache.sling.models.annotations.DefaultInjectionStrategy; |
| import org.apache.sling.models.annotations.Optional; |
| import org.apache.sling.models.annotations.Required; |
| import org.apache.sling.models.annotations.Source; |
| import org.apache.sling.models.annotations.Via; |
| import org.apache.sling.models.annotations.ViaProviderType; |
| import org.apache.sling.models.annotations.via.BeanProperty; |
| import org.apache.sling.models.impl.ModelAdapterFactory; |
| import org.apache.sling.models.impl.ReflectionUtil; |
| import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor; |
| import org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor2; |
| import org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| @SuppressWarnings("deprecation") |
| abstract class AbstractInjectableElement implements InjectableElement { |
| |
| private final AnnotatedElement element; |
| private final Type type; |
| private final String name; |
| private final String source; |
| private final ViaSpec via; |
| private final boolean hasDefaultValue; |
| private final Object defaultValue; |
| private final boolean isOptional; |
| private final boolean isRequired; |
| private final DefaultInjectionStrategy injectionStrategy; |
| private final DefaultInjectionStrategy defaultInjectionStrategy; |
| |
| private static final Logger log = LoggerFactory.getLogger(ModelAdapterFactory.class); |
| |
| public AbstractInjectableElement(AnnotatedElement element, Type type, String defaultName, |
| StaticInjectAnnotationProcessorFactory[] processorFactories, DefaultInjectionStrategy defaultInjectionStrategy) { |
| this.element = element; |
| this.type = type; |
| InjectAnnotationProcessor2 annotationProcessor = getAnnotationProcessor(element, processorFactories); |
| this.name = getName(element, defaultName, annotationProcessor); |
| this.source = getSource(element); |
| this.via = getVia(element, annotationProcessor); |
| this.hasDefaultValue = getHasDefaultValue(element, annotationProcessor); |
| this.defaultValue = getDefaultValue(element, type, annotationProcessor); |
| this.isOptional = getOptional(element, annotationProcessor); |
| this.isRequired = getRequired(element, annotationProcessor); |
| this.injectionStrategy = getInjectionStrategy(element, annotationProcessor, defaultInjectionStrategy); |
| this.defaultInjectionStrategy = defaultInjectionStrategy; |
| } |
| |
| private static InjectAnnotationProcessor2 getAnnotationProcessor(AnnotatedElement element, StaticInjectAnnotationProcessorFactory[] processorFactories) { |
| for (StaticInjectAnnotationProcessorFactory processorFactory : processorFactories) { |
| InjectAnnotationProcessor2 annotationProcessor = processorFactory.createAnnotationProcessor(element); |
| if (annotationProcessor != null) { |
| return annotationProcessor; |
| } |
| } |
| return null; |
| } |
| |
| @SuppressWarnings("unused") |
| private static String getName(AnnotatedElement element, String defaultName, InjectAnnotationProcessor2 annotationProcessor) { |
| String name = null; |
| if (annotationProcessor != null) { |
| name = annotationProcessor.getName(); |
| } |
| if (name == null) { |
| Named namedAnnotation = element.getAnnotation(Named.class); |
| if (namedAnnotation != null) { |
| name = namedAnnotation.value(); |
| } |
| else { |
| name = defaultName; |
| } |
| } |
| return name; |
| } |
| |
| @SuppressWarnings("unused") |
| private static String getSource(AnnotatedElement element) { |
| Source source = ReflectionUtil.getAnnotation(element, Source.class); |
| if (source != null) { |
| return source.value(); |
| } |
| return null; |
| } |
| |
| private static ViaSpec getVia(AnnotatedElement element, InjectAnnotationProcessor2 annotationProcessor) { |
| ViaSpec spec = new ViaSpec(); |
| if (annotationProcessor != null) { |
| spec.via = annotationProcessor.getVia(); |
| } |
| if (spec.via == null) { |
| Via viaAnnotation = element.getAnnotation(Via.class); |
| if (viaAnnotation != null) { |
| spec.via = viaAnnotation.value(); |
| spec.type = viaAnnotation.type(); |
| } |
| } else { |
| // use default type |
| spec.type = BeanProperty.class; |
| } |
| return spec; |
| } |
| |
| private static boolean getHasDefaultValue(AnnotatedElement element, InjectAnnotationProcessor2 annotationProcessor) { |
| if (annotationProcessor != null) { |
| return annotationProcessor.hasDefault(); |
| } |
| return element.isAnnotationPresent(Default.class); |
| } |
| |
| @SuppressWarnings("unused") |
| private static Object getDefaultValue(AnnotatedElement element, Type type, InjectAnnotationProcessor2 annotationProcessor) { |
| if (annotationProcessor != null && annotationProcessor.hasDefault()) { |
| return annotationProcessor.getDefault(); |
| } |
| |
| Default defaultAnnotation = element.getAnnotation(Default.class); |
| if (defaultAnnotation == null) { |
| return null; |
| } |
| |
| Object value = null; |
| |
| if (type instanceof Class) { |
| Class<?> injectedClass = (Class<?>) type; |
| if (injectedClass.isArray()) { |
| Class<?> componentType = injectedClass.getComponentType(); |
| if (componentType == String.class) { |
| value = defaultAnnotation.values(); |
| } else if (componentType == Integer.TYPE) { |
| value = defaultAnnotation.intValues(); |
| } else if (componentType == Integer.class) { |
| value = ArrayUtils.toObject(defaultAnnotation.intValues()); |
| } else if (componentType == Long.TYPE) { |
| value = defaultAnnotation.longValues(); |
| } else if (componentType == Long.class) { |
| value = ArrayUtils.toObject(defaultAnnotation.longValues()); |
| } else if (componentType == Boolean.TYPE) { |
| value = defaultAnnotation.booleanValues(); |
| } else if (componentType == Boolean.class) { |
| value = ArrayUtils.toObject(defaultAnnotation.booleanValues()); |
| } else if (componentType == Short.TYPE) { |
| value = defaultAnnotation.shortValues(); |
| } else if (componentType == Short.class) { |
| value = ArrayUtils.toObject(defaultAnnotation.shortValues()); |
| } else if (componentType == Float.TYPE) { |
| value = defaultAnnotation.floatValues(); |
| } else if (componentType == Float.class) { |
| value = ArrayUtils.toObject(defaultAnnotation.floatValues()); |
| } else if (componentType == Double.TYPE) { |
| value = defaultAnnotation.doubleValues(); |
| } else if (componentType == Double.class) { |
| value = ArrayUtils.toObject(defaultAnnotation.doubleValues()); |
| } else { |
| log.warn("Default values for {} are not supported", componentType); |
| } |
| } else { |
| if (injectedClass == String.class) { |
| value = defaultAnnotation.values().length == 0 ? "" : defaultAnnotation.values()[0]; |
| } else if (injectedClass == Integer.class) { |
| value = defaultAnnotation.intValues().length == 0 ? 0 : defaultAnnotation.intValues()[0]; |
| } else if (injectedClass == Long.class) { |
| value = defaultAnnotation.longValues().length == 0 ? 0l : defaultAnnotation.longValues()[0]; |
| } else if (injectedClass == Boolean.class) { |
| value = defaultAnnotation.booleanValues().length == 0 ? false : defaultAnnotation.booleanValues()[0]; |
| } else if (injectedClass == Short.class) { |
| value = defaultAnnotation.shortValues().length == 0 ? ((short) 0) : defaultAnnotation.shortValues()[0]; |
| } else if (injectedClass == Float.class) { |
| value = defaultAnnotation.floatValues().length == 0 ? 0f : defaultAnnotation.floatValues()[0]; |
| } else if (injectedClass == Double.class) { |
| value = defaultAnnotation.doubleValues().length == 0 ? 0d : defaultAnnotation.doubleValues()[0]; |
| } else { |
| log.warn("Default values for {} are not supported", injectedClass); |
| } |
| } |
| } else { |
| log.warn("Cannot provide default for {}", type); |
| } |
| return value; |
| } |
| |
| private static boolean getOptional(AnnotatedElement element, InjectAnnotationProcessor annotationProcessor) { |
| if (element.isAnnotationPresent(Optional.class)) { |
| return true; |
| } |
| if (annotationProcessor != null) { |
| Boolean optional = annotationProcessor.isOptional(); |
| if (optional != null) { |
| return optional.booleanValue(); |
| } |
| } |
| return false; |
| } |
| |
| private static boolean getRequired(AnnotatedElement element, InjectAnnotationProcessor annotationProcessor) { |
| // do not evaluate the injector-specific annotation (those are only considered for optional) |
| // even setting optional=false will not make an attribute mandatory |
| return element.isAnnotationPresent(Required.class); |
| } |
| |
| private static DefaultInjectionStrategy getInjectionStrategy(AnnotatedElement element, InjectAnnotationProcessor annotationProcessor, DefaultInjectionStrategy defaultInjectionStrategy) { |
| if (annotationProcessor != null) { |
| if (annotationProcessor instanceof InjectAnnotationProcessor2) { |
| switch (((InjectAnnotationProcessor2)annotationProcessor).getInjectionStrategy()) { |
| case OPTIONAL: |
| return DefaultInjectionStrategy.OPTIONAL; |
| case REQUIRED: |
| return DefaultInjectionStrategy.REQUIRED; |
| case DEFAULT: |
| break; |
| } |
| } |
| } |
| return defaultInjectionStrategy; |
| } |
| |
| @Override |
| public final AnnotatedElement getAnnotatedElement() { |
| return this.element; |
| } |
| |
| @Override |
| public final Type getType() { |
| return type; |
| } |
| |
| @Override |
| public final String getName() { |
| return this.name; |
| } |
| |
| @Override |
| public String getSource() { |
| return this.source; |
| } |
| |
| @Override |
| public String getVia() { |
| return this.via.via; |
| } |
| |
| @Override |
| public Class<? extends ViaProviderType> getViaProviderType() { return this.via.type; } |
| |
| @Override |
| public boolean hasDefaultValue() { |
| return this.hasDefaultValue; |
| } |
| |
| @Override |
| public Object getDefaultValue() { |
| return this.defaultValue; |
| } |
| |
| @Override |
| public boolean isOptional(InjectAnnotationProcessor annotationProcessor) { |
| DefaultInjectionStrategy injectionStrategy = this.injectionStrategy; |
| boolean isOptional = this.isOptional; |
| boolean isRequired = this.isRequired; |
| |
| // evaluate annotationProcessor (which depends on the adapter) |
| if (annotationProcessor != null) { |
| isOptional = getOptional(getAnnotatedElement(), annotationProcessor); |
| isRequired = getRequired(getAnnotatedElement(), annotationProcessor); |
| injectionStrategy = getInjectionStrategy(element, annotationProcessor, defaultInjectionStrategy); |
| } |
| if (injectionStrategy == DefaultInjectionStrategy.REQUIRED) { |
| return isOptional; |
| } else { |
| return !isRequired; |
| } |
| } |
| |
| private static class ViaSpec { |
| String via; |
| Class<? extends ViaProviderType> type; |
| } |
| |
| } |