--- a/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForComplexProperty.java +++ b/logback-core/src/main/java/ch/qos/logback/core/joran/action/IADataForComplexProperty.java @@ -26,6 +26,7 @@ public class IADataForComplexProperty { final AggregationType aggregationType; final String complexPropertyName; private Object nestedComplexProperty; + private Class expectedPropertyType; boolean inError; public IADataForComplexProperty(PropertySetter parentBean, AggregationType aggregationType, String complexPropertyName) { @@ -46,6 +47,14 @@ public class IADataForComplexProperty { return complexPropertyName; } + public Class getExpectedPropertyType() { + return expectedPropertyType; + } + + public void setExpectedPropertyType(Class expectedPropertyType) { + this.expectedPropertyType = expectedPropertyType; + } + public void setNestedComplexProperty(Object nestedComplexProperty) { this.nestedComplexProperty = nestedComplexProperty; } --- a/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComplexPropertyIA.java +++ b/logback-core/src/main/java/ch/qos/logback/core/joran/action/NestedComplexPropertyIA.java @@ -76,7 +76,9 @@ public class NestedComplexPropertyIA extends ImplicitAction { // we only push action data if NestComponentIA is applicable case AS_COMPLEX_PROPERTY_COLLECTION: case AS_COMPLEX_PROPERTY: + Class propertyType = parentBean.getTypeForComplexProperty(nestedElementTagName, aggregationType); IADataForComplexProperty ad = new IADataForComplexProperty(parentBean, aggregationType, nestedElementTagName); + ad.setExpectedPropertyType(propertyType); actionDataStack.push(ad); return true; @@ -118,7 +120,11 @@ public class NestedComplexPropertyIA extends ImplicitAction { addInfo("Assuming default type [" + componentClass.getName() + "] for [" + localName + "] property"); } - actionData.setNestedComplexProperty(componentClass.newInstance()); + Class expectedPropertyType = actionData.getExpectedPropertyType(); + + Object object = OptionHelper.instantiateClassWithSuperclassRestriction(componentClass, expectedPropertyType); + + actionData.setNestedComplexProperty(object); // pass along the repository if (actionData.getNestedComplexProperty() instanceof ContextAware) { --- a/logback-core/src/main/java/ch/qos/logback/core/joran/util/PropertySetter.java +++ b/logback-core/src/main/java/ch/qos/logback/core/joran/util/PropertySetter.java @@ -395,4 +395,36 @@ public class PropertySetter extends ContextAwareBase { return getByConcreteType(name, relevantMethod); } + public Class getTypeForComplexProperty(String nestedElementTagName, AggregationType aggregationType) { + + Method aMethod = null; + switch (aggregationType) { + case AS_COMPLEX_PROPERTY: + aMethod = findSetterMethod(nestedElementTagName); + break; + case AS_COMPLEX_PROPERTY_COLLECTION: + aMethod = findAdderMethod(nestedElementTagName); + } + + + checkParameterCount(aMethod, nestedElementTagName); + + Class[] paramTypes = aMethod.getParameterTypes(); + return paramTypes[0]; + + } + + private void checkParameterCount(Method aMethod, String nestedElementTagName) { + if(aMethod == null) { + String msg = "Could not find method for property [" + nestedElementTagName + "]."; + addError(msg); + throw new IllegalStateException(msg); + } + int parameterCount = aMethod.getParameterCount(); + if (parameterCount != 1) { + String msg = "Expected ["+aMethod.getName()+"] for property [" + nestedElementTagName + "] to have exactly one parameter."; + addError(msg); + throw new IllegalStateException(msg); + } + } } --- a/logback-core/src/main/java/ch/qos/logback/core/util/OptionHelper.java +++ b/logback-core/src/main/java/ch/qos/logback/core/util/OptionHelper.java @@ -14,6 +14,7 @@ package ch.qos.logback.core.util; import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; import java.util.Properties; import ch.qos.logback.core.Context; @@ -44,6 +45,19 @@ public class OptionHelper { return instantiateByClassNameAndParameter(className, superClass, classLoader, null, null); } + public static Object instantiateClassWithSuperclassRestriction(Class classObj, Class superClass) + throws IncompatibleClassException, DynamicClassLoadingException { + if (!superClass.isAssignableFrom(classObj)) { + throw new IncompatibleClassException(superClass, classObj); + } + + try { + return classObj.getConstructor().newInstance(); + } catch (NoSuchMethodException|InstantiationException|IllegalAccessException|InvocationTargetException e) { + throw new DynamicClassLoadingException("Failed to instantiate type " + classObj.getName(), e); + } + } + public static Object instantiateByClassNameAndParameter(String className, Class superClass, ClassLoader classLoader, Class type, Object parameter) throws IncompatibleClassException, DynamicClassLoadingException {