1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.rat.config.parameters;
21
22 import java.lang.reflect.Field;
23 import java.lang.reflect.Method;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.Collections;
27 import java.util.List;
28
29 import org.apache.commons.lang3.StringUtils;
30 import org.apache.commons.text.WordUtils;
31 import org.apache.rat.ConfigurationException;
32 import org.apache.rat.ImplementationException;
33 import org.apache.rat.analysis.IHeaderMatcher;
34 import org.apache.rat.license.ILicense;
35
36 import static java.lang.String.format;
37
38
39
40
41 public final class DescriptionBuilder {
42 private DescriptionBuilder() {
43
44 }
45
46
47
48
49
50
51
52 public static Description build(final Object object) {
53 if (object instanceof ILicense) {
54 ILicense license = (ILicense) object;
55 Class<?> clazz = object.getClass();
56 ConfigComponent configComponent = clazz.getAnnotation(ConfigComponent.class);
57 if (configComponent == null || configComponent.type() != ComponentType.LICENSE) {
58 throw new ConfigurationException(
59 format("Licenses must have License type specified in ConfigComponent annotation. Annotation missing or incorrect in %s", clazz));
60 }
61 List<Description> children = getConfigComponents(object.getClass());
62 return new Description(ComponentType.LICENSE, license.getId(), license.getName(), false, null, children, false);
63 }
64 return buildMap(object.getClass());
65 }
66
67 private static String fixupMethodName(final Method method) {
68 String name = method.getName();
69 if (name.startsWith("get") || name.startsWith("set") || name.startsWith("add")) {
70 if (name.length() > 3) {
71 return WordUtils.uncapitalize(name.substring(3));
72 }
73 }
74 throw new ImplementationException(format("'%s' is not a recognized method name", name));
75 }
76
77
78
79
80
81 static List<Description> getConfigComponents(final Class<?> clazz) {
82 if (clazz == null || clazz == String.class || clazz == Object.class) {
83 return Collections.emptyList();
84 }
85 List<Description> result = new ArrayList<>();
86 for (Field field : clazz.getDeclaredFields()) {
87 ConfigComponent configComponent = field.getAnnotation(ConfigComponent.class);
88 if (configComponent != null) {
89 String name = StringUtils.isBlank(configComponent.name()) ? field.getName() : configComponent.name();
90 Class<?> childClazz = configComponent.parameterType() == void.class ? field.getType()
91 : configComponent.parameterType();
92 boolean isCollection = Iterable.class.isAssignableFrom(field.getType());
93
94 Description desc = new Description(configComponent.type(), name, configComponent.desc(), isCollection,
95 childClazz, getConfigComponents(childClazz), configComponent.required());
96 result.add(desc);
97 }
98 }
99 for (Method method : clazz.getDeclaredMethods()) {
100 ConfigComponent configComponent = method.getAnnotation(ConfigComponent.class);
101 if (configComponent != null) {
102 String name = StringUtils.isBlank(configComponent.name()) ? fixupMethodName(method) : configComponent.name();
103 Class<?> childClazz = configComponent.parameterType() == void.class ? method.getReturnType()
104 : configComponent.parameterType();
105 boolean isCollection = Iterable.class.isAssignableFrom(method.getReturnType());
106
107 Description desc = new Description(configComponent.type(), name, configComponent.desc(), isCollection,
108 childClazz, getConfigComponents(childClazz), configComponent.required());
109 result.add(desc);
110 }
111 }
112 result.addAll(getConfigComponents(clazz.getSuperclass()));
113 Arrays.stream(clazz.getInterfaces()).forEach(c -> result.addAll(getConfigComponents(c)));
114 return result;
115 }
116
117 private static ConfigComponent findConfigComponent(final Class<?> clazz) {
118 if (clazz == null || clazz == String.class || clazz == Object.class) {
119 return null;
120 }
121 ConfigComponent configComponent = clazz.getAnnotation(ConfigComponent.class);
122 return configComponent == null ? findConfigComponent(clazz.getSuperclass()) : configComponent;
123 }
124
125 public static Class<?> getBuiltClass(final Class<? extends IHeaderMatcher.Builder> clazz) {
126 try {
127 MatcherBuilder matcherBuilder = clazz.getAnnotation(MatcherBuilder.class);
128 if (matcherBuilder == null) {
129 return clazz.getMethod("build").getReturnType();
130 } else {
131 return matcherBuilder.value();
132 }
133 } catch (NoSuchMethodException | SecurityException e) {
134 throw new IllegalStateException("The 'build' method of the Builder interface must always be public");
135 }
136 }
137
138
139
140
141
142
143 public static Description buildMap(final Class<?> clazz) {
144 if (clazz == IHeaderMatcher.class) {
145 throw new ImplementationException("'clazz' parameter must not be IHeaderMatcher.class but may be a child of it");
146 }
147 Class<?> workingClass = IHeaderMatcher.Builder.class.isAssignableFrom(clazz)
148 ? getBuiltClass((Class<IHeaderMatcher.Builder>) clazz)
149 : clazz;
150
151 ConfigComponent configComponent = findConfigComponent(workingClass);
152 if (configComponent == null) {
153 return null;
154 }
155 List<Description> children = getConfigComponents(workingClass);
156
157 return new Description(configComponent, false, null, children);
158 }
159 }