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 case AS_BASIC_PROPERTY_COLLECTION:
72 case AS_COMPLEX_PROPERTY_COLLECTION:
73 addError("Unexpected AggregationType " + type);
74 }
75 }
76
77 Method setter = findSetterMethod(name);
78 if (setter != null) {
79 return computeRawAggregationType(setter);
80 } else {
81
82 return AggregationType.NOT_FOUND;
83 }
84 }
85
86
87
88
89
90
91 public Method findAdderMethod(String name) {
92 String propertyName = BeanUtil.toLowerCamelCase(name);
93 return beanDescription.getAdder(propertyName);
94 }
95
96 public Method findSetterMethod(String name) {
97 String propertyName = BeanUtil.toLowerCamelCase(name);
98 return beanDescription.getSetter(propertyName);
99 }
100
101 private AggregationType computeRawAggregationType(Method method) {
102 Class<?> parameterClass = getParameterClassForMethod(method);
103 if (parameterClass == null) {
104 return AggregationType.NOT_FOUND;
105 }
106 if (StringToObjectConverter.canBeBuiltFromSimpleString(parameterClass)) {
107 return AggregationType.AS_BASIC_PROPERTY;
108 } else {
109 return AggregationType.AS_COMPLEX_PROPERTY;
110 }
111 }
112
113 private Class<?> getParameterClassForMethod(Method method) {
114 if (method == null) {
115 return null;
116 }
117 Class<?>[] classArray = method.getParameterTypes();
118 if (classArray.length != 1) {
119 return null;
120 } else {
121 return classArray[0];
122 }
123 }
124
125 public Class<?> getClassNameViaImplicitRules(String name, AggregationType aggregationType,
126 DefaultNestedComponentRegistry registry) {
127
128 Class<?> registryResult = registry.findDefaultComponentType(objClass, name);
129 if (registryResult != null) {
130 return registryResult;
131 }
132
133 Method relevantMethod = getRelevantMethod(name, aggregationType);
134 if (relevantMethod == null) {
135 return null;
136 }
137 Class<?> byAnnotation = getDefaultClassNameByAnnonation(name, relevantMethod);
138 if (byAnnotation != null) {
139 return byAnnotation;
140 }
141 return getByConcreteType(name, relevantMethod);
142 }
143
144 <T extends Annotation> T getAnnotation(String name, Class<T> annonationClass, Method relevantMethod) {
145
146 if (relevantMethod != null) {
147 return relevantMethod.getAnnotation(annonationClass);
148 } else {
149 return null;
150 }
151 }
152
153 Class<?> getDefaultClassNameByAnnonation(String name, Method relevantMethod) {
154 DefaultClass defaultClassAnnon = getAnnotation(name, DefaultClass.class, relevantMethod);
155 if (defaultClassAnnon != null) {
156 return defaultClassAnnon.value();
157 }
158 return null;
159 }
160 Method getRelevantMethod(String name, AggregationType aggregationType) {
161 Method relevantMethod;
162 if (aggregationType == AggregationType.AS_COMPLEX_PROPERTY_COLLECTION) {
163 relevantMethod = findAdderMethod(name);
164 } else if (aggregationType == AggregationType.AS_COMPLEX_PROPERTY) {
165 relevantMethod = findSetterMethod(name);
166 } else {
167 throw new IllegalStateException(aggregationType + " not allowed here");
168 }
169 return relevantMethod;
170 }
171
172 Class<?> getByConcreteType(String name, Method relevantMethod) {
173
174 Class<?> paramType = getParameterClassForMethod(relevantMethod);
175 if (paramType == null) {
176 return null;
177 }
178
179 boolean isUnequivocallyInstantiable = isUnequivocallyInstantiable(paramType);
180 if (isUnequivocallyInstantiable) {
181 return paramType;
182 } else {
183 return null;
184 }
185 }
186
187
188
189
190
191
192
193 private boolean isUnequivocallyInstantiable(Class<?> clazz) {
194 if (clazz.isInterface()) {
195 return false;
196 }
197
198
199
200 Object o;
201 try {
202 o = clazz.getDeclaredConstructor().newInstance();
203 if (o != null) {
204 return true;
205 } else {
206 return false;
207 }
208 } catch (InstantiationException | IllegalAccessException | InvocationTargetException
209 | NoSuchMethodException e) {
210 return false;
211 }
212 }
213 }