1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package ch.qos.logback.core.joran.util;
16
17 import ch.qos.logback.core.joran.spi.DefaultClass;
18 import ch.qos.logback.core.joran.spi.DefaultNestedComponentRegistry;
19 import ch.qos.logback.core.joran.util.beans.BeanDescription;
20 import ch.qos.logback.core.joran.util.beans.BeanDescriptionCache;
21 import ch.qos.logback.core.joran.util.beans.BeanUtil;
22 import ch.qos.logback.core.spi.ContextAwareBase;
23 import ch.qos.logback.core.util.AggregationType;
24 import ch.qos.logback.core.util.StringUtil;
25
26 import java.lang.annotation.Annotation;
27 import java.lang.reflect.InvocationTargetException;
28 import java.lang.reflect.Method;
29
30
31
32
33
34
35
36
37
38
39 public class AggregationAssessor extends ContextAwareBase {
40
41 protected final Class<?> objClass;
42 protected final BeanDescription beanDescription;
43
44 public AggregationAssessor(BeanDescriptionCache beanDescriptionCache, Class objClass) {
45 this.objClass = objClass;
46 this.beanDescription = beanDescriptionCache.getBeanDescription(objClass);
47 }
48
49
50
51
52
53
54
55
56 public AggregationType computeAggregationType(String name) {
57 String cName = StringUtil.capitalizeFirstLetter(name);
58
59 Method addMethod = findAdderMethod(cName);
60
61 if (addMethod != null) {
62 AggregationType type = computeRawAggregationType(addMethod);
63 switch (type) {
64 case NOT_FOUND:
65 return AggregationType.NOT_FOUND;
66 case AS_BASIC_PROPERTY:
67 return AggregationType.AS_BASIC_PROPERTY_COLLECTION;
68
69 case AS_COMPLEX_PROPERTY:
70 return AggregationType.AS_COMPLEX_PROPERTY_COLLECTION;
71
72
73 case AS_BASIC_PROPERTY_COLLECTION:
74 case AS_COMPLEX_PROPERTY_COLLECTION:
75 addError("Unexpected AggregationType " + type);
76 }
77 }
78
79 Method setter = findSetterMethod(name);
80 if (setter != null) {
81 return computeRawAggregationType(setter);
82 } else {
83
84 return AggregationType.NOT_FOUND;
85 }
86 }
87
88
89
90
91
92
93 public Method findAdderMethod(String name) {
94 String propertyName = BeanUtil.toLowerCamelCase(name);
95 return beanDescription.getAdder(propertyName);
96 }
97
98 public Method findSetterMethod(String name) {
99 String propertyName = BeanUtil.toLowerCamelCase(name);
100 return beanDescription.getSetter(propertyName);
101 }
102
103 private AggregationType computeRawAggregationType(Method method) {
104 Class<?> parameterClass = getParameterClassForMethod(method);
105 if (parameterClass == null) {
106 return AggregationType.NOT_FOUND;
107 }
108 if (StringToObjectConverter.canBeBuiltFromSimpleString(parameterClass)) {
109 return AggregationType.AS_BASIC_PROPERTY;
110 } else {
111 return AggregationType.AS_COMPLEX_PROPERTY;
112 }
113 }
114
115 private Class<?> getParameterClassForMethod(Method method) {
116 if (method == null) {
117 return null;
118 }
119 Class<?>[] classArray = method.getParameterTypes();
120 if (classArray.length != 1) {
121 return null;
122 } else {
123 return classArray[0];
124 }
125 }
126
127 public Class<?> getClassNameViaImplicitRules(String name, AggregationType aggregationType,
128 DefaultNestedComponentRegistry registry) {
129
130 Class<?> registryResult = registry.findDefaultComponentType(objClass, name);
131 if (registryResult != null) {
132 return registryResult;
133 }
134
135 Method relevantMethod = getRelevantMethod(name, aggregationType);
136 if (relevantMethod == null) {
137 return null;
138 }
139 Class<?> byAnnotation = getDefaultClassNameByAnnonation(name, relevantMethod);
140 if (byAnnotation != null) {
141 return byAnnotation;
142 }
143 return getByConcreteType(name, relevantMethod);
144 }
145
146 <T extends Annotation> T getAnnotation(String name, Class<T> annonationClass, Method relevantMethod) {
147
148 if (relevantMethod != null) {
149 return relevantMethod.getAnnotation(annonationClass);
150 } else {
151 return null;
152 }
153 }
154
155 Class<?> getDefaultClassNameByAnnonation(String name, Method relevantMethod) {
156 DefaultClass defaultClassAnnon = getAnnotation(name, DefaultClass.class, relevantMethod);
157 if (defaultClassAnnon != null) {
158 return defaultClassAnnon.value();
159 }
160 return null;
161 }
162 Method getRelevantMethod(String name, AggregationType aggregationType) {
163 Method relevantMethod;
164 if (aggregationType == AggregationType.AS_COMPLEX_PROPERTY_COLLECTION) {
165 relevantMethod = findAdderMethod(name);
166 } else if (aggregationType == AggregationType.AS_COMPLEX_PROPERTY) {
167 relevantMethod = findSetterMethod(name);
168 } else {
169 throw new IllegalStateException(aggregationType + " not allowed here");
170 }
171 return relevantMethod;
172 }
173
174 Class<?> getByConcreteType(String name, Method relevantMethod) {
175
176 Class<?> paramType = getParameterClassForMethod(relevantMethod);
177 if (paramType == null) {
178 return null;
179 }
180
181 boolean isUnequivocallyInstantiable = isUnequivocallyInstantiable(paramType);
182 if (isUnequivocallyInstantiable) {
183 return paramType;
184 } else {
185 return null;
186 }
187 }
188
189
190
191
192
193
194
195 private boolean isUnequivocallyInstantiable(Class<?> clazz) {
196 if (clazz.isInterface()) {
197 return false;
198 }
199
200
201
202 Object o;
203 try {
204 o = clazz.getDeclaredConstructor().newInstance();
205 if (o != null) {
206 return true;
207 } else {
208 return false;
209 }
210 } catch (InstantiationException | IllegalAccessException | InvocationTargetException
211 | NoSuchMethodException e) {
212 return false;
213 }
214 }
215 }