Return-Path: X-Original-To: apmail-sling-commits-archive@www.apache.org Delivered-To: apmail-sling-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 72A09178F2 for ; Fri, 3 Oct 2014 18:09:56 +0000 (UTC) Received: (qmail 89132 invoked by uid 500); 3 Oct 2014 18:09:56 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 89080 invoked by uid 500); 3 Oct 2014 18:09:56 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 89071 invoked by uid 99); 3 Oct 2014 18:09:56 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 03 Oct 2014 18:09:56 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 03 Oct 2014 18:09:53 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 3B08F2388999; Fri, 3 Oct 2014 18:09:33 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1629277 - in /sling/trunk/bundles/extensions/models: api/src/main/java/org/apache/sling/models/factory/ impl/src/main/java/org/apache/sling/models/impl/ impl/src/test/java/org/apache/sling/models/impl/ impl/src/test/java/org/apache/sling/m... Date: Fri, 03 Oct 2014 18:09:32 -0000 To: commits@sling.apache.org From: justin@apache.org X-Mailer: svnmailer-1.0.9 Message-Id: <20141003180933.3B08F2388999@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: justin Date: Fri Oct 3 18:09:32 2014 New Revision: 1629277 URL: http://svn.apache.org/r1629277 Log: SLING-3709 - adding additional testing for missing elements and post construct failures Added: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/FailingPostConstuctModel.java - copied, changed from r1629167, sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidModelException.java sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/MissingElementsException.java sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java?rev=1629277&r1=1629276&r2=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java (original) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java Fri Oct 3 18:09:32 2014 @@ -25,7 +25,7 @@ package org.apache.sling.models.factory; * @see ModelFactory * */ -public class InvalidAdaptableException extends RuntimeException { +public final class InvalidAdaptableException extends RuntimeException { private static final long serialVersionUID = -1209301268928038702L; public InvalidAdaptableException(String message) { Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidModelException.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidModelException.java?rev=1629277&r1=1629276&r2=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidModelException.java (original) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidModelException.java Fri Oct 3 18:09:32 2014 @@ -25,7 +25,7 @@ package org.apache.sling.models.factory; * * @see ModelFactory */ -public class InvalidModelException extends RuntimeException { +public final class InvalidModelException extends RuntimeException { private static final long serialVersionUID = 4323592065808565135L; Modified: sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/MissingElementsException.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/MissingElementsException.java?rev=1629277&r1=1629276&r2=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/MissingElementsException.java (original) +++ sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/MissingElementsException.java Fri Oct 3 18:09:32 2014 @@ -21,7 +21,6 @@ package org.apache.sling.models.factory; import java.lang.reflect.AnnotatedElement; import java.util.Collection; - /** * Exception which is triggered whenever a Sling Model cannot be instantiated * due to some missing elements (i.e. required fields/methods/constructor params @@ -30,31 +29,31 @@ import java.util.Collection; * @see ModelFactory * */ -public class MissingElementsException extends RuntimeException { +public final class MissingElementsException extends RuntimeException { private static final long serialVersionUID = 7870762030809272254L; - + private final Collection missingElements; private String formatString; private Class type; - + public MissingElementsException(String format, Collection elements, Class type) { super(); this.formatString = format; this.missingElements = elements; this.type = type; } - + @Override public String getMessage() { return String.format(formatString, missingElements, type); } - + public Class getType() { return type; } - + public Collection getMissingElements() { return missingElements; } Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java?rev=1629277&r1=1629276&r2=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/ModelAdapterFactory.java Fri Oct 3 18:09:32 2014 @@ -166,7 +166,7 @@ public class ModelAdapterFactory impleme public AdapterType getAdapter(Object adaptable, Class type) { Result result = internalCreateModel(adaptable, type); - result.logFailure(log); + result.logFailures(log); return result.getModel(); } @@ -174,12 +174,16 @@ public class ModelAdapterFactory impleme public ModelType createModel(Object adaptable, Class type) throws MissingElementsException, InvalidAdaptableException, InvalidModelException { Result result = internalCreateModel(adaptable, type); - result.throwException(); + result.throwException(log); return result.getModel(); } @Override public boolean canCreateFromAdaptable(Class modelClass, Object adaptable) throws InvalidModelException { + return innerCanCreateFromAdaptable(modelClass, adaptable); + } + + private static boolean innerCanCreateFromAdaptable(Class modelClass, Object adaptable) throws InvalidModelException { Model modelAnnotation = modelClass.getAnnotation(Model.class); if (modelAnnotation == null) { throw new InvalidModelException(String.format("Model class '%s' does not have a model annotation", modelClass)); @@ -196,7 +200,11 @@ public class ModelAdapterFactory impleme @Override public boolean isModelClass(Class modelClass) { - return modelClass.getAnnotation(Model.class) != null; + return innerIsModelClass(modelClass); + } + + private static boolean innerIsModelClass(Class clazz) { + return clazz.getAnnotation(Model.class) != null; } @SuppressWarnings("unchecked") @@ -206,7 +214,7 @@ public class ModelAdapterFactory impleme if (threadInvocationCounter.isMaximumReached()) { String msg = String.format("Adapting %s to %s failed, too much recursive invocations (>=%s).", new Object[] { adaptable, type, threadInvocationCounter.maxRecursionDepth }); - result.setFailure(FailureType.OTHER, msg); + result.addFailure(FailureType.OTHER, msg); return result; }; threadInvocationCounter.increase(); @@ -216,11 +224,10 @@ public class ModelAdapterFactory impleme if (implementationType != null) { type = (Class) implementationType; } - result.setType(type); Model modelAnnotation = type.getAnnotation(Model.class); if (modelAnnotation == null) { - result.setFailure(FailureType.NO_MODEL_ANNOTATION); + result.addFailure(FailureType.NO_MODEL_ANNOTATION, type); return result; } boolean isAdaptable = false; @@ -232,7 +239,7 @@ public class ModelAdapterFactory impleme } } if (!isAdaptable) { - result.setFailure(FailureType.ADAPTABLE_DOES_NOT_MATCH); + result.addFailure(FailureType.ADAPTABLE_DOES_NOT_MATCH, type); } else if (type.isInterface()) { InvocationHandler handler = createInvocationHandler(adaptable, type, modelAnnotation, result); if (handler != null) { @@ -245,7 +252,7 @@ public class ModelAdapterFactory impleme result.setModel(model); return result; } catch (Exception e) { - result.setFailure(FailureType.OTHER, "Unable to create object", e); + result.addFailure(FailureType.OTHER, "Unable to create object", e); } } return result; @@ -293,12 +300,13 @@ public class ModelAdapterFactory impleme * Is called each time when the given value should be injected into the given element * @param element * @param value + * @param result * @return true if injection was successful otherwise false */ - public boolean inject(AnnotatedElement element, Object value); + public boolean inject(AnnotatedElement element, Object value, Result result); } - private static class SetFieldCallback implements InjectCallback { + private class SetFieldCallback implements InjectCallback { private final Object object; @@ -307,12 +315,12 @@ public class ModelAdapterFactory impleme } @Override - public boolean inject(AnnotatedElement element, Object value) { - return setField((Field) element, object, value); + public boolean inject(AnnotatedElement element, Object value, Result result) { + return setField((Field) element, object, value, result); } } - private static class SetMethodsCallback implements InjectCallback { + private class SetMethodsCallback implements InjectCallback { private final Map methods; @@ -321,12 +329,12 @@ public class ModelAdapterFactory impleme } @Override - public boolean inject(AnnotatedElement element, Object value) { - return setMethod((Method) element, methods, value); + public boolean inject(AnnotatedElement element, Object value, Result result) { + return setMethod((Method) element, methods, value, result); } } - private static class SetConstructorParameterCallback implements InjectCallback { + private class SetConstructorParameterCallback implements InjectCallback { private final List parameterValues; @@ -335,14 +343,14 @@ public class ModelAdapterFactory impleme } @Override - public boolean inject(AnnotatedElement element, Object value) { - return setConstructorParameter((ConstructorParameter)element, parameterValues, value); + public boolean inject(AnnotatedElement element, Object value, Result result) { + return setConstructorParameter((ConstructorParameter)element, parameterValues, value, result); } } private boolean injectElement(final AnnotatedElement element, final Object adaptable, final Type type, final boolean injectPrimitiveInitialValue, final Model modelAnnotation, final DisposalCallbackRegistry registry, - final InjectCallback callback) { + final InjectCallback callback, Result result) { InjectAnnotationProcessor annotationProcessor = null; String source = getSource(element); @@ -365,7 +373,7 @@ public class ModelAdapterFactory impleme if (source == null || source.equals(injector.getName())) { if (name != null || injector instanceof AcceptsNullName) { Object value = injector.getValue(injectionAdaptable, name, type, element, registry); - if (callback.inject(element, value)) { + if (callback.inject(element, value, result)) { wasInjectionSuccessful = true; break; } @@ -375,14 +383,14 @@ public class ModelAdapterFactory impleme } // if injection failed, use default if (!wasInjectionSuccessful) { - wasInjectionSuccessful = injectDefaultValue(element, type, annotationProcessor, callback); + wasInjectionSuccessful = injectDefaultValue(element, type, annotationProcessor, callback, result); } // if default is not set, check if mandatory if (!wasInjectionSuccessful) { if (isOptional(element, modelAnnotation, annotationProcessor)) { if (injectPrimitiveInitialValue) { - injectPrimitiveInitialValue(element, type, callback); + injectPrimitiveInitialValue(element, type, callback, result); } } else { return false; @@ -409,13 +417,13 @@ public class ModelAdapterFactory impleme if (returnType != genericReturnType) { isPrimitive = true; } - if (!injectElement(method, adaptable, returnType, isPrimitive, modelAnnotation, registry, callback)) { + if (!injectElement(method, adaptable, returnType, isPrimitive, modelAnnotation, registry, callback, result)) { requiredMethods.add(method); } } registry.seal(); if (!requiredMethods.isEmpty()) { - result.setFailure(FailureType.MISSING_METHODS, requiredMethods); + result.addFailure(FailureType.MISSING_METHODS, requiredMethods, type); return null; } return handler; @@ -464,7 +472,7 @@ public class ModelAdapterFactory impleme Constructor constructorToUse = getBestMatchingConstructor(adaptable, type); if (constructorToUse == null) { - result.setFailure(FailureType.NO_USABLE_CONSTRUCTOR); + result.addFailure(FailureType.NO_USABLE_CONSTRUCTOR, type); return null; } @@ -502,21 +510,24 @@ public class ModelAdapterFactory impleme Set injectableFields = collectInjectableFields(type); for (Field field : injectableFields) { Type fieldType = mapPrimitiveClasses(field.getGenericType()); - if (!injectElement(field, adaptable, fieldType, false, modelAnnotation, registry, callback)) { + if (!injectElement(field, adaptable, fieldType, false, modelAnnotation, registry, callback, result)) { requiredFields.add(field); } } registry.seal(); if (!requiredFields.isEmpty()) { - result.setFailure(FailureType.MISSING_FIELDS, requiredFields); + result.addFailure(FailureType.MISSING_FIELDS, requiredFields, type); return null; } try { invokePostConstruct(object); return object; - } catch (Exception e) { - result.setFailure(FailureType.FAILED_CALLING_POST_CONSTRUCT, e); + } catch (InvocationTargetException e) { + result.addFailure(FailureType.FAILED_CALLING_POST_CONSTRUCT, e.getCause()); + return null; + } catch (IllegalAccessException e) { + result.addFailure(FailureType.FAILED_CALLING_POST_CONSTRUCT, e); return null; } @@ -575,12 +586,12 @@ public class ModelAdapterFactory impleme } ConstructorParameter constructorParameter = new ConstructorParameter( constructor.getParameterAnnotations()[i], constructor.getParameterTypes()[i], genericType, i); - if (!injectElement(constructorParameter, adaptable, genericType, isPrimitive, modelAnnotation, registry, callback)) { + if (!injectElement(constructorParameter, adaptable, genericType, isPrimitive, modelAnnotation, registry, callback, result)) { requiredParameters.add(constructorParameter); } } if (!requiredParameters.isEmpty()) { - result.setFailure(FailureType.MISSING_CONSTRUCTOR_PARAMS, requiredParameters); + result.addFailure(FailureType.MISSING_CONSTRUCTOR_PARAMS, requiredParameters, type); return null; } return constructor.newInstance(paramValues.toArray(new Object[paramValues.size()])); @@ -602,11 +613,11 @@ public class ModelAdapterFactory impleme } private boolean injectDefaultValue(AnnotatedElement point, Type type, InjectAnnotationProcessor processor, - InjectCallback callback) { + InjectCallback callback, Result result) { if (processor != null) { if (processor.hasDefault()) { - return callback.inject(point, processor.getDefault()); + return callback.inject(point, processor.getDefault(), result); } } Default defaultAnnotation = point.getAnnotation(Default.class); @@ -675,7 +686,7 @@ public class ModelAdapterFactory impleme log.warn("Cannot provide default for {}", type); return false; } - return callback.inject(point, value); + return callback.inject(point, value, result); } /** @@ -685,8 +696,9 @@ public class ModelAdapterFactory impleme * @param point Annotated element * @param wrapperType Non-primitive wrapper class for primitive class * @param callback Inject callback + * @param result */ - private void injectPrimitiveInitialValue(AnnotatedElement point, Type wrapperType, InjectCallback callback) { + private void injectPrimitiveInitialValue(AnnotatedElement point, Type wrapperType, InjectCallback callback, Result result) { Type primitiveType = mapWrapperClasses(wrapperType); Object value = null; if (primitiveType == int.class) { @@ -707,7 +719,7 @@ public class ModelAdapterFactory impleme value = Character.valueOf('\u0000'); } if (value != null) { - callback.inject(point, value); + callback.inject(point, value, result); }; } @@ -783,7 +795,7 @@ public class ModelAdapterFactory impleme return true; } - private void invokePostConstruct(Object object) throws Exception { + private void invokePostConstruct(Object object) throws InvocationTargetException, IllegalAccessException { Class clazz = object.getClass(); List postConstructMethods = new ArrayList(); while (clazz != null) { @@ -827,9 +839,9 @@ public class ModelAdapterFactory impleme } } - private static boolean setField(Field field, Object createdObject, Object value) { + private boolean setField(Field field, Object createdObject, Object value, Result result) { if (value != null) { - value = adaptIfNecessary(value, field.getType(), field.getGenericType()); + value = adaptIfNecessary(value, field.getType(), field.getGenericType(), result); // value may now be null due to the adaptation done above if (value == null) { return false; @@ -854,9 +866,9 @@ public class ModelAdapterFactory impleme } } - private static boolean setMethod(Method method, Map methods, Object value) { + private boolean setMethod(Method method, Map methods, Object value, Result result) { if (value != null) { - value = adaptIfNecessary(value, method.getReturnType(), method.getGenericReturnType()); + value = adaptIfNecessary(value, method.getReturnType(), method.getGenericReturnType(), result); // value may now be null due to the adaptation done above if (value == null) { return false; @@ -868,9 +880,9 @@ public class ModelAdapterFactory impleme } } - private static boolean setConstructorParameter(ConstructorParameter constructorParameter, List parameterValues, Object value) { + private boolean setConstructorParameter(ConstructorParameter constructorParameter, List parameterValues, Object value, Result result) { if (value != null && constructorParameter.getType() instanceof Class) { - value = adaptIfNecessary(value, (Class) constructorParameter.getType(), constructorParameter.getGenericType()); + value = adaptIfNecessary(value, (Class) constructorParameter.getType(), constructorParameter.getGenericType(), result); // value may now be null due to the adaptation done above if (value == null) { return false; @@ -882,10 +894,18 @@ public class ModelAdapterFactory impleme } } - private static Object adaptIfNecessary(Object value, Class type, Type genericType) { + private Object adaptIfNecessary(Object value, Class type, Type genericType, Result parentResult) { if (!isAcceptableType(type, genericType, value)) { Class declaredType = type; - if (value instanceof Adaptable) { + if (isModelClass(type) && canCreateFromAdaptable(type, value)) { + Result result = internalCreateModel(value, type); + if (result.getModel() == null) { + parentResult.appendFailures(result); + value = null; + } else { + value = result.getModel(); + } + } else if (value instanceof Adaptable) { value = ((Adaptable) value).adaptTo(type); } else if (genericType instanceof ParameterizedType) { ParameterizedType parameterizedType = (ParameterizedType) genericType; Modified: sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java?rev=1629277&r1=1629276&r2=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/main/java/org/apache/sling/models/impl/Result.java Fri Oct 3 18:09:32 2014 @@ -19,6 +19,8 @@ package org.apache.sling.models.impl; import java.lang.reflect.AnnotatedElement; +import java.util.ArrayList; +import java.util.List; import java.util.Set; import org.apache.sling.models.factory.InvalidAdaptableException; @@ -33,9 +35,9 @@ public class Result { "Failure calling post-construct method"), NO_MODEL_ANNOTATION( "Provided Adapter class does not have a Model annotation"), NO_USABLE_CONSTRUCTOR( "Unable to find a useable constructor"), OTHER("Unclassified problem"), MISSING_METHODS( - "Required methods %s on model interface %s were not able to be injected."), MISSING_FIELDS( - "Required fields %s on model interface %s were not able to be injected."), MISSING_CONSTRUCTOR_PARAMS( - "Required constructor parameteres %s on model interface %s were not able to be injected."); + "Required methods %s on model %s were not able to be injected."), MISSING_FIELDS( + "Required fields %s on model %s were not able to be injected."), MISSING_CONSTRUCTOR_PARAMS( + "Required constructor parameteres %s on model %s were not able to be injected."); private String message; @@ -43,98 +45,146 @@ public class Result { this.message = msg; } } + + private static class Failure { + private FailureType failureType; - private Exception failureException; + private Throwable failureException; - private String failureMessage; + private String failureMessage; - private FailureType failureType; + private Set missingElements; - private ModelType model; + private Class clazz; - private Class type; + private String getMessage() { + if (failureMessage != null) { + return failureMessage; + } else if (failureType != null) { + return failureType.message; + } else { + return null; + } + } - private Set missingElements; + public void log(Logger log) { - public ModelType getModel() { - return model; - } - - public void logFailure(Logger log) { - if (failureType != null) { - switch (failureType) { - case MISSING_CONSTRUCTOR_PARAMS: - case MISSING_FIELDS: - case MISSING_METHODS: - log.error(String.format(failureType.message, missingElements, type)); - break; - default: - log.error(getMessage(), failureException); - break; + if (failureType != null) { + switch (failureType) { + case MISSING_CONSTRUCTOR_PARAMS: + case MISSING_FIELDS: + case MISSING_METHODS: + log.error(String.format(failureType.message, missingElements, clazz)); + break; + default: + log.error(getMessage(), failureException); + break; + } } } - } - public void setFailure(FailureType type) { - this.failureType = type; + public void throwException() { + RuntimeException e = null; + if (failureType != null) { + final String msg = getMessage(); + switch (failureType) { + case ADAPTABLE_DOES_NOT_MATCH: + e = new InvalidAdaptableException(msg); + break; + case FAILED_CALLING_POST_CONSTRUCT: + case NO_MODEL_ANNOTATION: + case NO_USABLE_CONSTRUCTOR: + e = new InvalidModelException(msg); + break; + case MISSING_CONSTRUCTOR_PARAMS: + case MISSING_FIELDS: + case MISSING_METHODS: + e = new MissingElementsException(failureType.message, missingElements, clazz); + break; + default: + e = new RuntimeException(msg); + break; + } + } + if (e != null) { + if (failureException != null) { + e.initCause(failureException); + } + throw e; + } + } + } - public void setFailure(FailureType type, Exception e) { - this.failureType = type; - this.failureException = e; - } + private ModelType model; + + private List failures = new ArrayList(); - public void setFailure(FailureType type, Set requiredElements) { - this.failureType = type; - this.missingElements = requiredElements; + public ModelType getModel() { + return model; } - public void setFailure(FailureType type, String msg) { - this.failureType = type; - this.failureMessage = msg; + public void logFailures(Logger log) { + for (Failure failure : failures) { + failure.log(log); + } } - public void setFailure(FailureType type, String msg, Exception e) { - this.failureType = type; - this.failureMessage = msg; - this.failureException = e; + public void addFailure(FailureType type, Class clazz) { + Failure f = new Failure(); + f.failureType = type; + f.clazz = clazz; + failures.add(f); + } + + public void addFailure(FailureType type, Throwable e) { + Failure f = new Failure(); + f.failureType = type; + f.failureException = e; + failures.add(f); + } + + public void addFailure(FailureType type, Set requiredElements, Class clazz) { + Failure f = new Failure(); + f.failureType = type; + f.missingElements = requiredElements; + f.clazz = clazz; + failures.add(f); + } + + public void addFailure(FailureType type, String msg) { + Failure f = new Failure(); + f.failureType = type; + f.failureMessage = msg; + failures.add(f); + } + + public void addFailure(FailureType type, String msg, Throwable e) { + Failure f = new Failure(); + f.failureType = type; + f.failureMessage = msg; + f.failureException = e; + failures.add(f); } public void setModel(ModelType model) { this.model = model; } - +/* public void setType(Class type) { this.type = type; } - - public void throwException() { - if (failureType != null) { - final String msg = getMessage(); - switch (failureType) { - case ADAPTABLE_DOES_NOT_MATCH: - throw new InvalidAdaptableException(msg); - case FAILED_CALLING_POST_CONSTRUCT: - case NO_MODEL_ANNOTATION: - case NO_USABLE_CONSTRUCTOR: - throw new InvalidModelException(msg); - case MISSING_CONSTRUCTOR_PARAMS: - case MISSING_FIELDS: - case MISSING_METHODS: - throw new MissingElementsException(failureType.message, missingElements, type); - case OTHER: - throw new RuntimeException(msg); - } +*/ + public void throwException(Logger log) { + for (int i = 0; i < failures.size() - 1; i++) { + failures.get(i).log(log); + } + if (failures.size() >= 1) { + failures.get(failures.size() - 1).throwException(); } } - private String getMessage() { - if (failureMessage != null) { - return failureMessage; - } else if (failureType != null) { - return failureType.message; - } else { - return null; - } + public void appendFailures(Result result) { + failures.addAll(result.failures); } } Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java?rev=1629277&r1=1629276&r2=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/PostConstructTest.java Fri Oct 3 18:09:32 2014 @@ -22,6 +22,8 @@ import static org.mockito.Mockito.*; import java.util.Hashtable; import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.factory.InvalidModelException; +import org.apache.sling.models.testmodels.classes.FailingPostConstuctModel; import org.apache.sling.models.testmodels.classes.SubClass; import org.apache.sling.models.testmodels.classes.SubClassOverriddenPostConstruct; import org.junit.Before; @@ -41,33 +43,49 @@ public class PostConstructTest { @Mock private BundleContext bundleContext; + @Mock + private Resource resource; + + ModelAdapterFactory factory = new ModelAdapterFactory(); + @Before public void setup() { when(componentCtx.getBundleContext()).thenReturn(bundleContext); when(componentCtx.getProperties()).thenReturn(new Hashtable()); + factory.activate(componentCtx); + // no injectors are necessary } @Test public void testClassOrder() { - Resource r = mock(Resource.class); - ModelAdapterFactory factory = new ModelAdapterFactory(); - factory.activate(componentCtx); - // no injectors are necessary - - SubClass sc = factory.getAdapter(r, SubClass.class); + SubClass sc = factory.getAdapter(resource, SubClass.class); assertTrue(sc.getPostConstructCalledTimestampInSub() > sc.getPostConstructCalledTimestampInSuper()); assertTrue(sc.getPostConstructCalledTimestampInSuper() > 0); } - + @Test public void testOverriddenPostConstruct() { - Resource r = mock(Resource.class); - ModelAdapterFactory factory = new ModelAdapterFactory(); - factory.activate(componentCtx); - // no injectors are necessary - - SubClassOverriddenPostConstruct sc = factory.getAdapter(r, SubClassOverriddenPostConstruct.class); + SubClassOverriddenPostConstruct sc = factory.getAdapter(resource, SubClassOverriddenPostConstruct.class); assertEquals("Post construct not called exactly one time in sub class!", 1, sc.getPostConstructorCalledCounter()); assertEquals("Post construct was called on super class although overridden in sub class", 0, sc.getPostConstructCalledTimestampInSuper()); } + + @Test + public void testPostConstructMethodWhichThrowsException() { + FailingPostConstuctModel model = factory.getAdapter(resource, FailingPostConstuctModel.class); + assertNull(model); + } + + @Test + public void testPostConstructMethodWhichThrowsExceptionThrowingException() { + boolean thrown = false; + try { + factory.createModel(resource, FailingPostConstuctModel.class); + } catch (InvalidModelException e) { + assertTrue(e.getMessage().contains("post-construct")); + assertEquals("FAIL", e.getCause().getMessage()); + thrown = true; + } + assertTrue(thrown); + } } Modified: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java?rev=1629277&r1=1629276&r2=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/impl/ResourceModelClassesTest.java Fri Oct 3 18:09:32 2014 @@ -19,6 +19,7 @@ package org.apache.sling.models.impl; import static org.junit.Assert.*; import static org.mockito.Mockito.*; +import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -29,6 +30,7 @@ import org.apache.commons.lang.RandomStr import org.apache.sling.api.resource.Resource; import org.apache.sling.api.resource.ValueMap; import org.apache.sling.api.wrappers.ValueMapDecorator; +import org.apache.sling.models.factory.MissingElementsException; import org.apache.sling.models.impl.injectors.ChildResourceInjector; import org.apache.sling.models.impl.injectors.ValueMapInjector; import org.apache.sling.models.testmodels.classes.ArrayPrimitivesModel; @@ -180,6 +182,29 @@ public class ResourceModelClassesTest { } @Test + public void testRequiredPropertyModelWithException() { + Map map = new HashMap(); + map.put("first", "first-value"); + map.put("third", "third-value"); + ValueMap vm = spy(new ValueMapDecorator(map)); + + Resource res = mock(Resource.class); + when(res.adaptTo(ValueMap.class)).thenReturn(vm); + + boolean thrown = false; + try { + factory.createModel(res, ResourceModelWithRequiredField.class); + } catch (MissingElementsException e) { + assertEquals(ResourceModelWithRequiredField.class, e.getType()); + assertEquals("required", ((Field) e.getMissingElements().iterator().next()).getName()); + thrown = true; + } + assertTrue(thrown); + + verify(vm).get("required", String.class); + } + + @Test public void testRequiredPropertyModelOptionalStrategyAvailable() { Map map = new HashMap(); map.put("first", "first-value"); Copied: sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/FailingPostConstuctModel.java (from r1629167, sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java) URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/FailingPostConstuctModel.java?p2=sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/FailingPostConstuctModel.java&p1=sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java&r1=1629167&r2=1629277&rev=1629277&view=diff ============================================================================== --- sling/trunk/bundles/extensions/models/api/src/main/java/org/apache/sling/models/factory/InvalidAdaptableException.java (original) +++ sling/trunk/bundles/extensions/models/impl/src/test/java/org/apache/sling/models/testmodels/classes/FailingPostConstuctModel.java Fri Oct 3 18:09:32 2014 @@ -16,19 +16,19 @@ * specific language governing permissions and limitations * under the License. */ -package org.apache.sling.models.factory; +package org.apache.sling.models.testmodels.classes; -/** - * Exception which is triggered whenever a Sling Model could not be - * instantiated because it could not be adapted from the given adaptable. - * - * @see ModelFactory - * - */ -public class InvalidAdaptableException extends RuntimeException { - private static final long serialVersionUID = -1209301268928038702L; +import javax.annotation.PostConstruct; + +import org.apache.sling.api.resource.Resource; +import org.apache.sling.models.annotations.Model; - public InvalidAdaptableException(String message) { - super(message); +@Model(adaptables=Resource.class) +public class FailingPostConstuctModel { + + @PostConstruct + protected void pc() throws Exception { + throw new Exception("FAIL"); } + }