use of org.apache.sling.models.spi.ValuePreparer in project sling by apache.
the class ModelAdapterFactory method injectElement.
@CheckForNull
private RuntimeException injectElement(final InjectableElement element, final Object adaptable, @Nonnull final DisposalCallbackRegistry registry, final InjectCallback callback, @Nonnull final Map<ValuePreparer, Object> preparedValues) {
InjectAnnotationProcessor annotationProcessor = null;
String source = element.getSource();
boolean wasInjectionSuccessful = false;
// find an appropriate annotation processor
for (InjectAnnotationProcessorFactory2 factory : injectAnnotationProcessorFactories2) {
annotationProcessor = factory.createAnnotationProcessor(adaptable, element.getAnnotatedElement());
if (annotationProcessor != null) {
break;
}
}
if (annotationProcessor == null) {
for (InjectAnnotationProcessorFactory factory : injectAnnotationProcessorFactories) {
annotationProcessor = factory.createAnnotationProcessor(adaptable, element.getAnnotatedElement());
if (annotationProcessor != null) {
break;
}
}
}
String name = getName(element, annotationProcessor);
final Object injectionAdaptable = getAdaptable(adaptable, element, annotationProcessor);
RuntimeException lastInjectionException = null;
if (injectionAdaptable != null) {
// prepare the set of injectors to process. if a source is given only use injectors with this name.
final RankedServices<Injector> injectorsToProcess;
if (StringUtils.isEmpty(source)) {
injectorsToProcess = sortedInjectors;
} else {
injectorsToProcess = injectors.get(source);
if (injectorsToProcess == null) {
throw new IllegalArgumentException("No Sling Models Injector registered for source '" + source + "'.");
}
}
// find the right injector
for (Injector injector : injectorsToProcess) {
if (name != null || injector instanceof AcceptsNullName) {
Object preparedValue = injectionAdaptable;
// only do the ValuePreparer optimization for the original adaptable
if (injector instanceof ValuePreparer && adaptable == injectionAdaptable) {
final ValuePreparer preparer = (ValuePreparer) injector;
Object fromMap = preparedValues.get(preparer);
if (fromMap != null) {
preparedValue = fromMap;
} else {
preparedValue = preparer.prepareValue(injectionAdaptable);
preparedValues.put(preparer, preparedValue);
}
}
Object value = injector.getValue(preparedValue, name, element.getType(), element.getAnnotatedElement(), registry);
if (value != null) {
lastInjectionException = callback.inject(element, value);
if (lastInjectionException == null) {
wasInjectionSuccessful = true;
break;
}
}
}
}
}
// if injection failed, use default
if (!wasInjectionSuccessful) {
Result<Boolean> defaultInjectionResult = injectDefaultValue(element, annotationProcessor, callback);
if (defaultInjectionResult.wasSuccessful()) {
wasInjectionSuccessful = defaultInjectionResult.getValue();
// log previous injection error, if there was any
if (lastInjectionException != null && wasInjectionSuccessful) {
log.debug("Although falling back to default value worked, injection into {} failed because of: " + lastInjectionException.getMessage(), element.getAnnotatedElement(), lastInjectionException);
}
} else {
return defaultInjectionResult.getThrowable();
}
}
// if default is not set, check if mandatory
if (!wasInjectionSuccessful) {
if (element.isOptional(annotationProcessor)) {
// log previous injection error, if there was any
if (lastInjectionException != null) {
log.debug("Injection into optional element {} failed because of: " + lastInjectionException.getMessage(), element.getAnnotatedElement(), lastInjectionException);
}
if (element.isPrimitive()) {
RuntimeException throwable = injectPrimitiveInitialValue(element, callback);
if (throwable != null) {
return throwable;
}
}
} else {
if (lastInjectionException != null) {
return lastInjectionException;
} else {
return new ModelClassException("No injector returned a non-null value!");
}
}
}
return null;
}
use of org.apache.sling.models.spi.ValuePreparer in project sling by apache.
the class ModelAdapterFactory method createObject.
private <ModelType> Result<ModelType> createObject(final Object adaptable, final ModelClass<ModelType> modelClass) throws InstantiationException, InvocationTargetException, IllegalAccessException {
DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
ModelClassConstructor<ModelType> constructorToUse = getBestMatchingConstructor(adaptable, modelClass);
if (constructorToUse == null) {
return new Result<ModelType>(new ModelClassException("Unable to find a useable constructor for model " + modelClass.getType()));
}
final Map<ValuePreparer, Object> preparedValues = new HashMap<ValuePreparer, Object>(VALUE_PREPARERS_COUNT);
final ModelType object;
if (constructorToUse.getConstructor().getParameterTypes().length == 0) {
// no parameters for constructor injection? instantiate it right away
object = constructorToUse.getConstructor().newInstance();
} else {
// if this fails, make sure resources that may be claimed by injectors are cleared up again
try {
Result<ModelType> result = newInstanceWithConstructorInjection(constructorToUse, adaptable, modelClass, registry, preparedValues);
if (!result.wasSuccessful()) {
registry.onDisposed();
return result;
} else {
object = result.getValue();
}
} catch (InstantiationException ex) {
registry.onDisposed();
throw ex;
} catch (InvocationTargetException ex) {
registry.onDisposed();
throw ex;
} catch (IllegalAccessException ex) {
registry.onDisposed();
throw ex;
}
}
registerCallbackRegistry(object, registry);
InjectCallback callback = new SetFieldCallback(object);
InjectableField[] injectableFields = modelClass.getInjectableFields();
MissingElementsException missingElements = new MissingElementsException("Could not inject all required fields into " + modelClass.getType());
for (InjectableField field : injectableFields) {
RuntimeException t = injectElement(field, adaptable, registry, callback, preparedValues);
if (t != null) {
missingElements.addMissingElementExceptions(new MissingElementException(field.getAnnotatedElement(), t));
}
}
registry.seal();
if (!missingElements.isEmpty()) {
return new Result<ModelType>(missingElements);
}
try {
invokePostConstruct(object);
} catch (InvocationTargetException e) {
return new Result<ModelType>(new PostConstructException("Post-construct method has thrown an exception for model " + modelClass.getType(), e.getCause()));
} catch (IllegalAccessException e) {
new Result<ModelType>(new ModelClassException("Could not call post-construct method for model " + modelClass.getType(), e));
}
return new Result<ModelType>(object);
}
use of org.apache.sling.models.spi.ValuePreparer in project sling by apache.
the class ModelAdapterFactory method createInvocationHandler.
private <ModelType> Result<InvocationHandler> createInvocationHandler(final Object adaptable, final ModelClass<ModelType> modelClass) {
InjectableMethod[] injectableMethods = modelClass.getInjectableMethods();
final Map<Method, Object> methods = new HashMap<Method, Object>();
SetMethodsCallback callback = new SetMethodsCallback(methods);
MapBackedInvocationHandler handler = new MapBackedInvocationHandler(methods);
DisposalCallbackRegistryImpl registry = new DisposalCallbackRegistryImpl();
registerCallbackRegistry(handler, registry);
final Map<ValuePreparer, Object> preparedValues = new HashMap<ValuePreparer, Object>(VALUE_PREPARERS_COUNT);
MissingElementsException missingElements = new MissingElementsException("Could not create all mandatory methods for interface of model " + modelClass);
for (InjectableMethod method : injectableMethods) {
RuntimeException t = injectElement(method, adaptable, registry, callback, preparedValues);
if (t != null) {
missingElements.addMissingElementExceptions(new MissingElementException(method.getAnnotatedElement(), t));
}
}
registry.seal();
if (!missingElements.isEmpty()) {
return new Result<InvocationHandler>(missingElements);
}
return new Result<InvocationHandler>(handler);
}
Aggregations