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 license) {
54 Class<?> clazz = object.getClass();
55 ConfigComponent configComponent = clazz.getAnnotation(ConfigComponent.class);
56 if (configComponent == null || configComponent.type() != ComponentType.LICENSE) {
57 throw new ConfigurationException(
58 format("Licenses must have License type specified in ConfigComponent annotation. Annotation missing or incorrect in %s", clazz));
59 }
60 List<Description> children = getConfigComponents(object.getClass());
61 return new Description(ComponentType.LICENSE, license.getId(), license.getName(), false, null, children, false);
62 }
63 return buildMap(object.getClass());
64 }
65
66 private static String fixupMethodName(final Method method) {
67 String name = method.getName();
68 if (name.startsWith("get") || name.startsWith("set") || name.startsWith("add")) {
69 if (name.length() > 3) {
70 return WordUtils.uncapitalize(name.substring(3));
71 }
72 }
73 throw new ImplementationException(format("'%s' is not a recognized method name", name));
74 }
75
76
77
78
79
80 static List<Description> getConfigComponents(final Class<?> clazz) {
81 if (clazz == null || clazz == String.class || clazz == Object.class) {
82 return Collections.emptyList();
83 }
84 List<Description> result = new ArrayList<>();
85 for (Field field : clazz.getDeclaredFields()) {
86 ConfigComponent configComponent = field.getAnnotation(ConfigComponent.class);
87 if (configComponent != null) {
88 String name = StringUtils.isBlank(configComponent.name()) ? field.getName() : configComponent.name();
89 Class<?> childClazz = configComponent.parameterType() == void.class ? field.getType()
90 : configComponent.parameterType();
91 boolean isCollection = Iterable.class.isAssignableFrom(field.getType());
92
93 Description desc = new Description(configComponent.type(), name, configComponent.desc(), isCollection,
94 childClazz, getConfigComponents(childClazz), configComponent.required());
95 result.add(desc);
96 }
97 }
98 for (Method method : clazz.getDeclaredMethods()) {
99 ConfigComponent configComponent = method.getAnnotation(ConfigComponent.class);
100 if (configComponent != null) {
101 String name = StringUtils.isBlank(configComponent.name()) ? fixupMethodName(method) : configComponent.name();
102 Class<?> childClazz = configComponent.parameterType() == void.class ? method.getReturnType()
103 : configComponent.parameterType();
104 boolean isCollection = Iterable.class.isAssignableFrom(method.getReturnType());
105
106 Description desc = new Description(configComponent.type(), name, configComponent.desc(), isCollection,
107 childClazz, getConfigComponents(childClazz), configComponent.required());
108 result.add(desc);
109 }
110 }
111 result.addAll(getConfigComponents(clazz.getSuperclass()));
112 Arrays.stream(clazz.getInterfaces()).forEach(c -> result.addAll(getConfigComponents(c)));
113 return result;
114 }
115
116 private static ConfigComponent findConfigComponent(final Class<?> clazz) {
117 if (clazz == null || clazz == String.class || clazz == Object.class) {
118 return null;
119 }
120 ConfigComponent configComponent = clazz.getAnnotation(ConfigComponent.class);
121 return configComponent == null ? findConfigComponent(clazz.getSuperclass()) : configComponent;
122 }
123
124 public static Class<?> getBuiltClass(final Class<? extends IHeaderMatcher.Builder> clazz) {
125 try {
126 MatcherBuilder matcherBuilder = clazz.getAnnotation(MatcherBuilder.class);
127 if (matcherBuilder == null) {
128 return clazz.getMethod("build").getReturnType();
129 } else {
130 return matcherBuilder.value();
131 }
132 } catch (NoSuchMethodException | SecurityException e) {
133 throw new IllegalStateException("The 'build' method of the Builder interface must always be public");
134 }
135 }
136
137
138
139
140
141
142 public static Description buildMap(final Class<?> clazz) {
143 if (clazz == IHeaderMatcher.class) {
144 throw new ImplementationException("'clazz' parameter must not be IHeaderMatcher.class but may be a child of it");
145 }
146 Class<?> workingClass = IHeaderMatcher.Builder.class.isAssignableFrom(clazz)
147 ? getBuiltClass((Class<IHeaderMatcher.Builder>) clazz)
148 : clazz;
149
150 ConfigComponent configComponent = findConfigComponent(workingClass);
151 if (configComponent == null) {
152 return null;
153 }
154 List<Description> children = getConfigComponents(workingClass);
155
156 return new Description(configComponent, false, null, children);
157 }
158 }