1. Project Clover database Wed Nov 12 2025 05:07:35 UTC
  2. Package guru.mikelue.foxglove.annotation

File DataGenContextImpl.java

 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

34
134
38
8
552
460
63
0.47
3.53
4.75
1.66

Classes

Class Line # Actions
DataGenContextImpl 27 38 0% 19 1
0.983050898.3%
SupplierFactory 188 27 0% 12 3
0.923076992.3%
SupplierFactoryOfDataGenerator 300 8 0% 4 0
1.0100%
SupplierFactoryOfTableFacet 336 23 0% 12 0
1.0100%
MemberAccessor 403 0 - 0 0
-1.0 -
AbstractMemberAccessor 411 9 0% 6 0
1.0100%
MethodAccessor 461 16 0% 5 0
1.0100%
FieldAccessor 511 13 0% 5 0
1.0100%
 

Contributing tests

This file is covered by 40 tests. .

Source view

1    package guru.mikelue.foxglove.annotation;
2   
3    import java.lang.annotation.Annotation;
4    import java.lang.reflect.*;
5    import java.util.HashMap;
6    import java.util.List;
7    import java.util.Map;
8    import java.util.Optional;
9    import java.util.function.Function;
10    import java.util.function.Predicate;
11    import java.util.stream.Stream;
12   
13    import org.apache.commons.lang3.Validate;
14    import org.apache.commons.lang3.builder.ToStringBuilder;
15    import org.apache.commons.lang3.builder.ToStringStyle;
16    import org.apache.commons.lang3.function.FailableFunction;
17    import org.apache.commons.lang3.reflect.FieldUtils;
18    import org.apache.commons.lang3.reflect.MethodUtils;
19    import org.slf4j.Logger;
20    import org.slf4j.LoggerFactory;
21   
22    import guru.mikelue.foxglove.DataGenerator;
23    import guru.mikelue.foxglove.TableFacet;
24    import guru.mikelue.foxglove.functional.DataGeneratorProvider;
25    import guru.mikelue.foxglove.functional.TableFacetsProvider;
26   
 
27    class DataGenContextImpl<T extends TableFacet> implements DataGenContext<T> {
28    private final SupplierFactory<TableFacetsSource, List<T>>
29    tableFacetsSuppliers = new SupplierFactoryOfTableFacet<>();
30   
31    private final SupplierFactory<DataGeneratorSource, DataGenerator<T>>
32    dataGeneratorSuppliers = new SupplierFactoryOfDataGenerator<>();
33   
 
34  53 toggle DataGenContextImpl(Class<?> testClass)
35    {
36  53 Predicate<Member> notPrivateMethodOfSuperclass = m -> {
37  618 var declaringClass = m.getDeclaringClass();
38   
39    // Same class always allowed
40  618 if (testClass.isAssignableFrom(declaringClass)) {
41  386 return true;
42    }
43   
44  232 var modifiers = m.getModifiers();
45    // Public/protected methods of superclass allowed
46  232 if ((modifiers & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
47  132 return true;
48    }
49   
50  100 if ((modifiers & Modifier.PRIVATE) != 0) {
51  66 return false;
52    }
53   
54  34 return testClass.getPackageName()
55    .equals(declaringClass.getPackageName());
56    };
57   
58  53 MethodUtils.getMethodsListWithAnnotation(
59    testClass, TableFacetsSource.class, true, true
60    )
61    .stream()
62    .filter(notPrivateMethodOfSuperclass)
63    .forEach(m -> {
64  267 tableFacetsSuppliers.addMethod(m);
65    });
66   
67  53 FieldUtils.getFieldsListWithAnnotation(
68    testClass, TableFacetsSource.class
69    )
70    .stream()
71    .filter(notPrivateMethodOfSuperclass)
72    .forEach(m -> {
73  262 tableFacetsSuppliers.addField(m);
74    });
75   
76  53 MethodUtils.getMethodsListWithAnnotation(
77    testClass, DataGeneratorSource.class, true, true
78    )
79    .stream()
80    .filter(notPrivateMethodOfSuperclass)
81    .forEach(m -> {
82  12 dataGeneratorSuppliers.addMethod(m);
83    });
84   
85  53 FieldUtils.getFieldsListWithAnnotation(
86    testClass, DataGeneratorSource.class
87    )
88    .stream()
89    .filter(notPrivateMethodOfSuperclass)
90    .forEach(m -> {
91  11 dataGeneratorSuppliers.addField(m);
92    });
93    }
94   
 
95  6 toggle @Override
96    public List<T> getTypedTableFacets(Class<? extends TableFacetsProvider<T>> clazz, Object testingInstance)
97    {
98  6 return initializeProvider(clazz, testingInstance)
99    .get();
100    }
101   
 
102  45 toggle @Override
103    public List<T> getNamedTableFacets(String name, Object testingInstance)
104    {
105  45 return tableFacetsSuppliers.grabInstance(name, testingInstance);
106    }
107   
 
108  4 toggle @Override
109    public DataGenerator<T> getTypedDataGenerator(Class<? extends DataGeneratorProvider<T>> clazz, Object testingInstance)
110    {
111  4 return initializeProvider(clazz, testingInstance)
112    .get();
113    }
114   
 
115  6 toggle @Override
116    public DataGenerator<T> getNamedDataGenerator(String name, Object testingInstance)
117    {
118  6 return dataGeneratorSuppliers.grabInstance(name, testingInstance);
119    }
120   
 
121  8 toggle @Override
122    public Optional<List<T>> getDefaultTableFacets(Object testingInstance)
123    {
124  8 return Optional.ofNullable(
125    tableFacetsSuppliers.grabSingleInstance(testingInstance)
126    );
127    }
128   
 
129  16 toggle @Override
130    public Optional<DataGenerator<T>> getDefaultDataGenerator(Object testingInstance)
131    {
132  16 return Optional.ofNullable(
133    dataGeneratorSuppliers.grabSingleInstance(testingInstance)
134    );
135    }
136   
 
137  5 toggle boolean hasNamedTableFacets(String name)
138    {
139  5 return tableFacetsSuppliers.hasSource(name);
140    }
141   
 
142  4 toggle boolean hasNamedDataGenerator(String name)
143    {
144  4 return dataGeneratorSuppliers.hasSource(name);
145    }
146   
 
147  10 toggle private static <T> T initializeProvider(
148    Class<T> clazz, Object testingInstance
149    ) {
150  10 try {
151  10 Constructor<T> constructor = getConstructorOf(clazz, testingInstance.getClass());
152  10 if (Modifier.isStatic(clazz.getModifiers()) ||
153    !clazz.isMemberClass()
154    ) {
155  5 return constructor.newInstance();
156    }
157   
158  5 return constructor.newInstance(testingInstance);
159    } catch (Exception e) {
160  0 throw new RuntimeException(
161    String.format("Failed to instantiate Provider<%s>.",
162    clazz.getSimpleName()
163    ),
164    e
165    );
166    }
167    }
168   
 
169  10 toggle private static <T> Constructor<T> getConstructorOf(
170    Class<T> targetClass, Class<?> enclosingClass
171    ) throws NoSuchMethodException {
172  10 Constructor<T> constructor = null;
173   
174  10 if (
175  10 Modifier.isStatic(targetClass.getModifiers()) ||
176    !targetClass.isMemberClass()
177    ) {
178  5 constructor = targetClass.getDeclaredConstructor(new Class<?>[0]);
179    } else {
180  5 constructor = targetClass.getDeclaredConstructor(enclosingClass);
181    }
182   
183  10 constructor.trySetAccessible();
184  10 return constructor;
185    }
186    }
187   
 
188    abstract class SupplierFactory<A extends Annotation, T> {
189    protected final static Logger logger = LoggerFactory.getLogger(SupplierFactory.class);
190   
191    private Map<String, FailableFunction<Object, T, Throwable>> functionOfSources = new HashMap<>();
192   
193    private Function<A, String> nameExtractor;
194    protected Class<A> annotationType;
195   
 
196  106 toggle SupplierFactory(
197    Class<A> annotationType, Function<A, String> nameExtractor
198    ) {
199  106 this.annotationType = annotationType;
200  106 this.nameExtractor = nameExtractor;
201    }
202   
 
203  279 toggle void addMethod(Method method)
204    {
205  279 var memberAccessor = new MethodAccessor<A>(method, annotationType, nameExtractor);
206   
207  279 Validate.isTrue(
208    method.getParameterCount() == 0,
209    "Method<%s> should not have parameters.", memberAccessor
210    );
211   
212  279 addMember(memberAccessor);
213    }
214   
 
215  273 toggle void addField(Field field)
216    {
217  273 addMember(new FieldAccessor<>(field, annotationType, nameExtractor));
218    }
219   
 
220  552 toggle private void addMember(MemberAccessor<?> memberAccessor)
221    {
222  552 validateAddedName(memberAccessor);
223  552 validateSupportedType(memberAccessor);
224   
225  552 var name = memberAccessor.getProviderName();
226  552 functionOfSources.put(name, buildGrabFunction(memberAccessor));
227   
228  552 if (logger.isDebugEnabled()) {
229  552 var modifiers = Modifier.toString(memberAccessor.getMember().getModifiers());
230  552 logger.debug("Adding source[{}]. <{}> {}.",
231    name, modifiers, memberAccessor
232    );
233    }
234    }
235   
 
236  9 toggle boolean hasSource(String name)
237    {
238  9 return functionOfSources.containsKey(name);
239    }
240   
 
241  51 toggle T grabInstance(String name, Object testingInstance)
242    {
243  51 Validate.isTrue(
244    functionOfSources.containsKey(name),
245    "No @%s found for name: [%s]",
246    annotationType.getSimpleName(), name
247    );
248   
249  51 try {
250  51 return functionOfSources.get(name).apply(testingInstance);
251    } catch (Throwable t) {
252  0 throw new RuntimeException(
253    String.format("Failed to execute @%s method for name: [%s]",
254    annotationType.getSimpleName(), name
255    ), t
256    );
257    }
258    }
259   
 
260  24 toggle T grabSingleInstance(Object testingInstance)
261    {
262  24 int numberOfSources = functionOfSources.size();
263   
264  24 Validate.isTrue(numberOfSources <= 1,
265    "Multiple members annotated by @%s are defined. Needs only one for default object resolving.",
266    annotationType.getSimpleName()
267    );
268   
269  24 if (numberOfSources == 0) {
270  6 return null;
271    }
272   
273  18 try {
274  18 return functionOfSources.values().iterator().next()
275    .apply(testingInstance);
276    } catch (Throwable t) {
277  0 throw new RuntimeException(
278    String.format("Failed to get single @%s source",
279    annotationType.getSimpleName()
280    ), t
281    );
282    }
283    }
284   
285    abstract protected void validateSupportedType(MemberAccessor<?> memberAccessor);
286   
287    abstract protected FailableFunction<Object, T, Throwable> buildGrabFunction(MemberAccessor<?> memberAccessor);
288   
 
289  552 toggle private void validateAddedName(MemberAccessor<?> memberAccessor)
290    {
291  552 var name = memberAccessor.getProviderName();
292   
293  552 Validate.isTrue(
294    !functionOfSources.containsKey(name),
295    "Duplicated: %s", memberAccessor
296    );
297    }
298    }
299   
 
300    class SupplierFactoryOfDataGenerator<T extends TableFacet> extends SupplierFactory<DataGeneratorSource, DataGenerator<T>> {
 
301  53 toggle SupplierFactoryOfDataGenerator()
302    {
303  53 super(DataGeneratorSource.class, DataGeneratorSource::value);
304    }
305   
 
306  23 toggle @Override
307    protected void validateSupportedType(MemberAccessor<?> memberAccessor)
308    {
309  23 var checkedType = memberAccessor.getSignificantType();
310   
311  23 Validate.isTrue(
312    DataGenerator.class.isAssignableFrom(checkedType) ||
313    DataGeneratorProvider.class.isAssignableFrom(checkedType),
314    "Member<%s> should be type of %2$s, DataGeneratorProvider<? extends TableFacet>(just for field). But got: \"%3$s\".",
315    memberAccessor, DataGenerator.class.getSimpleName(),
316    memberAccessor.getSignificantType().getSimpleName()
317    );
318    }
319   
 
320  23 toggle @Override
321    protected FailableFunction<Object, DataGenerator<T>, Throwable> buildGrabFunction(MemberAccessor<?> memberAccessor)
322    {
323  23 var checkedType = memberAccessor.getSignificantType();
324   
325  23 if (DataGeneratorProvider.class.isAssignableFrom(checkedType)) {
326  5 return instance -> memberAccessor.<DataGeneratorProvider<T>>grabValue(instance)
327    .get();
328    }
329   
330  18 return testingInstance -> {
331  18 return memberAccessor.grabValue(testingInstance);
332    };
333    }
334    }
335   
 
336    class SupplierFactoryOfTableFacet<T extends TableFacet> extends SupplierFactory<TableFacetsSource, List<T>> {
 
337  53 toggle SupplierFactoryOfTableFacet()
338    {
339  53 super(TableFacetsSource.class, TableFacetsSource::value);
340    }
341   
 
342  529 toggle @Override
343    protected void validateSupportedType(MemberAccessor<?> memberAccessor)
344    {
345  529 var checkedType = memberAccessor.getSignificantType();
346   
347  529 if (checkedType.isArray()) {
348  35 checkedType = checkedType.getComponentType();
349  494 } else if (
350  494 checkedType.isAssignableFrom(List.class) ||
351    checkedType.isAssignableFrom(Stream.class) ||
352    ( // Field supporting TableFacetsProvider<T>
353    memberAccessor instanceof FieldAccessor &&
354    TableFacetsProvider.class.isAssignableFrom(checkedType)
355    )
356    ) {
357  85 checkedType = memberAccessor.getGenericTypeOfFirstParameter();
358    }
359   
360  529 Validate.isTrue(
361    TableFacet.class.isAssignableFrom(checkedType),
362    "Member<%s> should be type of %2$s, List<%2$s>, Stream<%2$s>, %2$s[], or TableFacetsProvider<%2$s>(just for field). But got: \"%3$s\".",
363    memberAccessor, TableFacet.class.getSimpleName(),
364    memberAccessor.getSignificantType().getSimpleName()
365    );
366    }
367   
 
368  529 toggle @Override
369    protected FailableFunction<Object, List<T>, Throwable> buildGrabFunction(MemberAccessor<?> memberAccessor)
370    {
371  529 var checkedType = memberAccessor.getSignificantType();
372   
373  529 if (TableFacet.class.isAssignableFrom(checkedType)) {
374  409 return testingInstance -> {
375  38 T o = memberAccessor.grabValue(testingInstance);
376  38 return List.of(o);
377    };
378    }
379   
380  120 if (List.class.isAssignableFrom(checkedType)) {
381  34 return memberAccessor::grabValue;
382    }
383   
384  86 if (Stream.class.isAssignableFrom(checkedType)) {
385  34 return testingInstance -> {
386  3 Stream<T> streamOfFacets = memberAccessor.grabValue(testingInstance);
387  3 return streamOfFacets.toList();
388    };
389    }
390   
391  52 if (TableFacetsProvider.class.isAssignableFrom(checkedType)) {
392  17 return instance -> memberAccessor.<TableFacetsProvider<T>>grabValue(instance)
393    .get();
394    }
395   
396  35 return testingInstance -> {
397  4 T[] arrayOfFacets = memberAccessor.grabValue(testingInstance);
398  4 return List.of(arrayOfFacets);
399    };
400    }
401    }
402   
 
403    interface MemberAccessor<M extends Member & AnnotatedElement> {
404    Class<?> getSignificantType();
405    Class<?> getGenericTypeOfFirstParameter();
406    <T> T grabValue(Object instance) throws Throwable;
407    M getMember();
408    String getProviderName();
409    }
410   
 
411    abstract class AbstractMemberAccessor<M extends Member & AnnotatedElement, A extends Annotation> implements MemberAccessor<M> {
412    private final Class<A> annotationType;
413    private final Function<A, String> nameExtractor;
414    private FailableFunction<Object, ?, Throwable> invoker;
415   
 
416  552 toggle AbstractMemberAccessor(Class<A> annotationType, Function<A, String> nameExtractor)
417    {
418  552 this.annotationType = annotationType;
419  552 this.nameExtractor = nameExtractor;
420    }
421   
 
422  1104 toggle @Override
423    public String getProviderName()
424    {
425  1104 var member = getMember();
426  1104 var name = nameExtractor.apply(
427    member.getAnnotation(annotationType)
428    );
429   
430  1104 return !name.isEmpty() ? name : member.getName();
431    }
432   
 
433  552 toggle @Override
434    public String toString()
435    {
436  552 var member = getMember();
437   
438  552 return new ToStringBuilder(this, ToStringStyle.NO_CLASS_NAME_STYLE)
439    .append("@" + annotationType.getSimpleName())
440    .append(String.format("<%s> %s.%s",
441    member.getClass().getSimpleName(),
442    member.getDeclaringClass().getSimpleName(),
443    member.getName()
444    ))
445    .toString();
446    }
447   
 
448  69 toggle @SuppressWarnings("unchecked")
449    @Override
450    public <T> T grabValue(Object instance) throws Throwable
451    {
452  69 return (T)invoker.apply(instance);
453    }
454   
 
455  552 toggle final protected void setInvoker(FailableFunction<Object, ?, Throwable> invoker)
456    {
457  552 this.invoker = invoker;
458    }
459    }
460   
 
461    class MethodAccessor<A extends Annotation> extends AbstractMemberAccessor<Method, A> {
462    private final Method method;
463   
 
464  279 toggle MethodAccessor(Method method, Class<A> annotationType, Function<A, String> nameExtractor)
465    {
466  279 super(annotationType, nameExtractor);
467  279 this.method = method;
468   
469  279 FailableFunction<Object, ?, Throwable> invoker;
470  279 if (Modifier.isStatic(method.getModifiers())) {
471  85 invoker = instance -> {
472  5 var oldValue = method.canAccess(null);
473  5 method.setAccessible(true);
474   
475  5 try {
476  5 return method.invoke(null);
477    } finally {
478  5 method.setAccessible(oldValue);
479    }
480    };
481    } else {
482  194 invoker = instance ->
483    MethodUtils.invokeMethod(
484    instance, true, method.getName()
485    );
486    }
487   
488  279 setInvoker(invoker);
489    }
490   
 
491  837 toggle @Override
492    public Class<?> getSignificantType()
493    {
494  837 return method.getReturnType();
495    }
496   
 
497  36 toggle @Override
498    public Class<?> getGenericTypeOfFirstParameter()
499    {
500  36 var genericType = (ParameterizedType)method.getGenericReturnType();
501  36 return (Class<?>)genericType.getActualTypeArguments()[0];
502    }
503   
 
504  1116 toggle @Override
505    public Method getMember()
506    {
507  1116 return method;
508    }
509    }
510   
 
511    class FieldAccessor<A extends Annotation> extends AbstractMemberAccessor<Field, A> {
512    private final Field field;
513   
 
514  273 toggle FieldAccessor(Field field, Class<A> annotationType, Function<A, String> nameExtractor)
515    {
516  273 super(annotationType, nameExtractor);
517   
518  273 this.field = field;
519   
520  273 FailableFunction<Object, ?, Throwable> invoker;
521  273 if (Modifier.isStatic(field.getModifiers())) {
522  96 invoker = instance -> {
523  6 return FieldUtils.readStaticField(field, true);
524    };
525    } else {
526  177 invoker = instance -> {
527  19 return FieldUtils.readField(field, instance, true);
528    };
529    }
530   
531  273 setInvoker(invoker);
532    }
533   
 
534  819 toggle @Override
535    public Class<?> getSignificantType()
536    {
537  819 return field.getType();
538    }
539   
 
540  49 toggle @Override
541    public Class<?> getGenericTypeOfFirstParameter()
542    {
543  49 var genericType = (ParameterizedType)field.getGenericType();
544  49 return (Class<?>)genericType.getActualTypeArguments()[0];
545    }
546   
 
547  1092 toggle @Override
548    public Field getMember()
549    {
550  1092 return field;
551    }
552    }