Search in sources :

Example 1 with ModelClassException

use of org.apache.sling.models.factory.ModelClassException 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;
}
Also used : InjectAnnotationProcessorFactory2(org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory2) ValuePreparer(org.apache.sling.models.spi.ValuePreparer) InjectAnnotationProcessor(org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessor) Injector(org.apache.sling.models.spi.Injector) ModelClassException(org.apache.sling.models.factory.ModelClassException) AcceptsNullName(org.apache.sling.models.spi.AcceptsNullName) InjectAnnotationProcessorFactory(org.apache.sling.models.spi.injectorspecific.InjectAnnotationProcessorFactory) StaticInjectAnnotationProcessorFactory(org.apache.sling.models.spi.injectorspecific.StaticInjectAnnotationProcessorFactory) CheckForNull(javax.annotation.CheckForNull)

Example 2 with ModelClassException

use of org.apache.sling.models.factory.ModelClassException in project sling by apache.

the class ModelAdapterFactory method adapt.

/**
     * Preferably adapt via the {@link ModelFactory} in case the target type is a Sling Model itself, otherwise use regular {@link Adaptable#adaptTo(Class)}.
     * @param value the object from which to adapt
     * @param type the target type
     * @param isWithinCollection
     * @return a Result either encapsulating an exception or the adapted value
     */
@CheckForNull
private Result<Object> adapt(final Object value, final Class<?> type, boolean isWithinCollection) {
    Object adaptedValue = null;
    final String messageSuffix = isWithinCollection ? " in collection" : "";
    if (isModelClass(type) && canCreateFromAdaptable(value, type)) {
        Result<?> result = internalCreateModel(value, type);
        if (result.wasSuccessful()) {
            adaptedValue = result.getValue();
        } else {
            return new Result<Object>(new ModelClassException(String.format("Could not create model from %s: %s%s", value.getClass(), result.getThrowable().getMessage(), messageSuffix), result.getThrowable()));
        }
    } else if (value instanceof Adaptable) {
        adaptedValue = ((Adaptable) value).adaptTo(type);
        if (adaptedValue == null) {
            return new Result<Object>(new ModelClassException(String.format("Could not adapt from %s to %s%s", value.getClass(), type, messageSuffix)));
        }
    }
    if (adaptedValue != null) {
        return new Result<Object>(adaptedValue);
    } else {
        return new Result<Object>(new ModelClassException(String.format("Could not adapt from %s to %s%s, because this class is not adaptable!", value.getClass(), type, messageSuffix)));
    }
}
Also used : ModelClassException(org.apache.sling.models.factory.ModelClassException) Adaptable(org.apache.sling.api.adapter.Adaptable) CheckForNull(javax.annotation.CheckForNull)

Example 3 with ModelClassException

use of org.apache.sling.models.factory.ModelClassException in project sling by apache.

the class ModelAdapterFactory method injectPrimitiveInitialValue.

/**
     * Injects the default initial value for the given primitive class which
     * cannot be null (e.g. int = 0, boolean = false).
     * 
     * @param point Annotated element
     * @param callback Inject callback
     */
private RuntimeException injectPrimitiveInitialValue(InjectableElement point, InjectCallback callback) {
    Type primitiveType = ReflectionUtil.mapWrapperClasses(point.getType());
    Object value = null;
    if (primitiveType == int.class) {
        value = 0;
    } else if (primitiveType == long.class) {
        value = 0L;
    } else if (primitiveType == boolean.class) {
        value = Boolean.FALSE;
    } else if (primitiveType == double.class) {
        value = 0.0d;
    } else if (primitiveType == float.class) {
        value = 0.0f;
    } else if (primitiveType == short.class) {
        value = (short) 0;
    } else if (primitiveType == byte.class) {
        value = (byte) 0;
    } else if (primitiveType == char.class) {
        value = '';
    }
    if (value != null) {
        return callback.inject(point, value);
    } else {
        return new ModelClassException(String.format("Unknown primitive type %s", primitiveType.toString()));
    }
}
Also used : Type(java.lang.reflect.Type) ParameterizedType(java.lang.reflect.ParameterizedType) ViaProviderType(org.apache.sling.models.annotations.ViaProviderType) ModelClassException(org.apache.sling.models.factory.ModelClassException)

Example 4 with ModelClassException

use of org.apache.sling.models.factory.ModelClassException in project sling by apache.

the class ModelAdapterFactory method adaptIfNecessary.

private Result<Object> adaptIfNecessary(final Object value, final Class<?> type, final Type genericType) {
    final Object adaptedValue;
    if (!isAcceptableType(type, genericType, value)) {
        if (genericType instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericType;
            if (value instanceof Collection && (type.equals(Collection.class) || type.equals(List.class)) && parameterizedType.getActualTypeArguments().length == 1) {
                List<Object> result = new ArrayList<Object>();
                for (Object valueObject : (Collection<?>) value) {
                    Result<Object> singleValueResult = adapt(valueObject, (Class<?>) parameterizedType.getActualTypeArguments()[0], true);
                    if (singleValueResult.wasSuccessful()) {
                        result.add(singleValueResult.getValue());
                    } else {
                        return singleValueResult;
                    }
                }
                adaptedValue = result;
            } else {
                return new Result<Object>(new ModelClassException(String.format("%s is neither a parameterized Collection or List", type)));
            }
        } else {
            return adapt(value, type, false);
        }
        return new Result<Object>(adaptedValue);
    } else {
        return new Result<Object>(value);
    }
}
Also used : ParameterizedType(java.lang.reflect.ParameterizedType) ModelClassException(org.apache.sling.models.factory.ModelClassException) ArrayList(java.util.ArrayList) Collection(java.util.Collection)

Example 5 with ModelClassException

use of org.apache.sling.models.factory.ModelClassException in project sling by apache.

the class ModelAdapterFactory method internalCreateModel.

@SuppressWarnings("unchecked")
private <ModelType> Result<ModelType> internalCreateModel(final Object adaptable, final Class<ModelType> requestedType) {
    Result<ModelType> result;
    ThreadInvocationCounter threadInvocationCounter = invocationCountThreadLocal.get();
    if (threadInvocationCounter.isMaximumReached()) {
        String msg = String.format("Adapting %s to %s failed, too much recursive invocations (>=%s).", adaptable, requestedType, threadInvocationCounter.maxRecursionDepth);
        return new Result<ModelType>(new ModelClassException(msg));
    }
    threadInvocationCounter.increase();
    try {
        // check if a different implementation class was registered for this adapter type
        ModelClass<ModelType> modelClass = getImplementationTypeForAdapterType(requestedType, adaptable);
        if (!modelClass.hasModelAnnotation()) {
            String msg = String.format("Provided Adapter class does not have a Model annotation: %s", modelClass.getType());
            return new Result<ModelType>(new ModelClassException(msg));
        }
        boolean isAdaptable = false;
        Model modelAnnotation = modelClass.getModelAnnotation();
        if (modelAnnotation.cache()) {
            Map<Class, Object> adaptableCache = adapterCache.get(adaptable);
            if (adaptableCache != null) {
                ModelType cachedObject = (ModelType) adaptableCache.get(requestedType);
                if (cachedObject != null) {
                    return new Result<ModelType>(cachedObject);
                }
            }
        }
        Class<?>[] declaredAdaptable = modelAnnotation.adaptables();
        for (Class<?> clazz : declaredAdaptable) {
            if (clazz.isInstance(adaptable)) {
                isAdaptable = true;
            }
        }
        if (!isAdaptable) {
            String msg = String.format("Adaptables (%s) are not acceptable for the model class: %s", StringUtils.join(declaredAdaptable), modelClass.getType());
            return new Result<ModelType>(new InvalidAdaptableException(msg));
        } else {
            RuntimeException t = validateModel(adaptable, modelClass.getType(), modelAnnotation);
            if (t != null) {
                return new Result<ModelType>(t);
            }
            if (modelClass.getType().isInterface()) {
                Result<InvocationHandler> handlerResult = createInvocationHandler(adaptable, modelClass);
                if (handlerResult.wasSuccessful()) {
                    ModelType model = (ModelType) Proxy.newProxyInstance(modelClass.getType().getClassLoader(), new Class<?>[] { modelClass.getType() }, handlerResult.getValue());
                    if (modelAnnotation.cache()) {
                        Map<Class, Object> adaptableCache = adapterCache.get(adaptable);
                        if (adaptableCache == null) {
                            adaptableCache = new ConcurrentHashMap<Class, Object>(INNER_CACHE_INITIAL_CAPACITY);
                            adapterCache.put(adaptable, adaptableCache);
                        }
                        adaptableCache.put(requestedType, model);
                    }
                    result = new Result<ModelType>(model);
                } else {
                    return new Result<ModelType>(handlerResult.getThrowable());
                }
            } else {
                try {
                    result = createObject(adaptable, modelClass);
                    if (result.wasSuccessful() && modelAnnotation.cache()) {
                        Map<Class, Object> adaptableCache = adapterCache.get(adaptable);
                        if (adaptableCache == null) {
                            adaptableCache = new ConcurrentHashMap<Class, Object>(INNER_CACHE_INITIAL_CAPACITY);
                            adapterCache.put(adaptable, adaptableCache);
                        }
                        adaptableCache.put(requestedType, result.getValue());
                    }
                } catch (Exception e) {
                    String msg = String.format("Unable to create model %s", modelClass.getType());
                    return new Result<ModelType>(new ModelClassException(msg, e));
                }
            }
        }
        return result;
    } finally {
        threadInvocationCounter.decrease();
    }
}
Also used : InvocationHandler(java.lang.reflect.InvocationHandler) MissingElementException(org.apache.sling.models.factory.MissingElementException) InvalidAdaptableException(org.apache.sling.models.factory.InvalidAdaptableException) ValidationException(org.apache.sling.models.factory.ValidationException) ExportException(org.apache.sling.models.factory.ExportException) PostConstructException(org.apache.sling.models.factory.PostConstructException) InvocationTargetException(java.lang.reflect.InvocationTargetException) ModelClassException(org.apache.sling.models.factory.ModelClassException) MissingExporterException(org.apache.sling.models.factory.MissingExporterException) MissingElementsException(org.apache.sling.models.factory.MissingElementsException) InvalidModelException(org.apache.sling.models.factory.InvalidModelException) ModelClassException(org.apache.sling.models.factory.ModelClassException) Model(org.apache.sling.models.annotations.Model) ModelClass(org.apache.sling.models.impl.model.ModelClass) InvalidAdaptableException(org.apache.sling.models.factory.InvalidAdaptableException)

Aggregations

ModelClassException (org.apache.sling.models.factory.ModelClassException)7 InvocationTargetException (java.lang.reflect.InvocationTargetException)2 ParameterizedType (java.lang.reflect.ParameterizedType)2 CheckForNull (javax.annotation.CheckForNull)2 MissingElementException (org.apache.sling.models.factory.MissingElementException)2 MissingElementsException (org.apache.sling.models.factory.MissingElementsException)2 PostConstructException (org.apache.sling.models.factory.PostConstructException)2 ValuePreparer (org.apache.sling.models.spi.ValuePreparer)2 InvocationHandler (java.lang.reflect.InvocationHandler)1 Type (java.lang.reflect.Type)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 HashMap (java.util.HashMap)1 WeakHashMap (java.util.WeakHashMap)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 Adaptable (org.apache.sling.api.adapter.Adaptable)1 Resource (org.apache.sling.api.resource.Resource)1 Model (org.apache.sling.models.annotations.Model)1 ViaProviderType (org.apache.sling.models.annotations.ViaProviderType)1 ExportException (org.apache.sling.models.factory.ExportException)1