Result internalCreateModel()

in src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java [357:434]


    <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<>(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<>(new ModelClassException(msg));
            }
            boolean isAdaptable = false;

            Model modelAnnotation = modelClass.getModelAnnotation();
            Map<Class<?>, SoftReference<Object>> adaptableCache = null;

            if (modelAnnotation.cache()) {
                adaptableCache = getOrCreateCache(adaptable);
                SoftReference<Object> softReference = adaptableCache.get(modelClass.getType());
                if (softReference != null) {
                    ModelType cachedObject = (ModelType) softReference.get();
                    if (cachedObject != null) {
                        return new Result<>(cachedObject);
                    }
                }
            }

            Class<?>[] declaredAdaptable = modelAnnotation.adaptables();
            for (Class<?> clazz : declaredAdaptable) {
                if (clazz.isInstance(adaptable)) {
                    isAdaptable = true;
                }
            }
            if (!isAdaptable) {
                String msg = String.format("Given adaptable (%s) is not acceptable for the model class: %s which only supports adaptables %s", adaptable.getClass(), modelClass.getType(), StringUtils.join(declaredAdaptable));
                return new Result<>(new InvalidAdaptableException(msg));
            } else {
                RuntimeException t = validateModel(adaptable, modelClass.getType(), modelAnnotation);
                if (t != null) {
                    return new Result<>(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() && adaptableCache != null) {
                            adaptableCache.put(modelClass.getType(), new SoftReference<>(model));
                        }

                        result = new Result<>(model);
                    } else {
                        return new Result<>(handlerResult.getThrowable());
                    }
                } else {
                    try {
                        result = createObject(adaptable, modelClass);

                        if (result.wasSuccessful() && modelAnnotation.cache() && adaptableCache != null) {
                            adaptableCache.put(modelClass.getType(), new SoftReference<>(result.getValue()));
                        }
                    } catch (Exception e) {
                        String msg = String.format("Unable to create model %s", modelClass.getType());
                        return new Result<>(new ModelClassException(msg, e));
                    }
                }
            }
            return result;
        } finally {
            threadInvocationCounter.decrease();
        }
    }