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

File SpringContextObjectFactory.java

 

Coverage histogram

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

Code metrics

24
62
8
1
286
221
24
0.39
7.75
8
3

Classes

Class Line # Actions
SpringContextObjectFactory 34 62 0% 24 5
0.946808594.7%
 

Contributing tests

This file is covered by 11 tests. .

Source view

1    package guru.mikelue.foxglove.springframework;
2   
3    import java.util.ArrayList;
4    import java.util.Arrays;
5    import java.util.List;
6    import java.util.Optional;
7    import java.util.stream.Stream;
8   
9    import javax.sql.DataSource;
10   
11    import org.springframework.beans.factory.BeanNotOfRequiredTypeException;
12    import org.springframework.beans.factory.NoSuchBeanDefinitionException;
13    import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
14    import org.springframework.context.ApplicationContext;
15    import org.springframework.jdbc.datasource.DataSourceUtils;
16   
17    import org.slf4j.Logger;
18    import org.slf4j.LoggerFactory;
19   
20    import guru.mikelue.foxglove.DataGenerator;
21    import guru.mikelue.foxglove.TableFacet;
22    import guru.mikelue.foxglove.annotation.*;
23    import guru.mikelue.foxglove.functional.DataGeneratorProvider;
24    import guru.mikelue.foxglove.functional.TableFacetsProvider;
25    import guru.mikelue.foxglove.jdbc.JdbcDataGenerator;
26   
27    import static org.springframework.transaction.support.TransactionSynchronizationManager.isActualTransactionActive;
28   
29    /**
30    * A factory class which uses Spring {@link ApplicationContext} to
31    * create data generation objects defined by {@link GenData} or
32    * fallback to {@link ReflectGenDataObjectFactory}.
33    */
 
34    class SpringContextObjectFactory implements GenDataObjectFactory {
35    private final Logger logger = LoggerFactory.getLogger(SpringContextObjectFactory.class);
36   
37    private final ApplicationContext appContext;
38   
39    private final GenDataInspector genDataInspector;
40    private final DataGenContext<TableFacet> dataGenContext;
41    private final Object testingInstance;
42    private final String nameOfTestingObject;
43   
 
44  18 toggle SpringContextObjectFactory(
45    ApplicationContext appContext,
46    Object testingInstance, GenData genData,
47    DataGenContext<TableFacet> dataGenContext,
48    String name
49    ) {
50  18 this.appContext = appContext;
51  18 this.genDataInspector = GenDataInspector.of(genData);
52  18 this.dataGenContext = dataGenContext;
53  18 this.testingInstance = testingInstance;
54  18 this.nameOfTestingObject = name;
55    }
56   
 
57  13 toggle @SuppressWarnings("unchecked")
58    @Override
59    public DataGenerator<TableFacet> getDataGenerator() throws Exception
60    {
61  13 if (genDataInspector.useDefaultDataGenerator()) {
62    /*
63    * Tries to get the default data generator from Spring context first.
64    */
65  9 return getBeanIfUnique(DataGeneratorProvider.class) // Uses provider if available
66    .map(providerBean -> (DataGenerator<TableFacet>)providerBean.get())
67    .or(() -> (Optional<DataGenerator<TableFacet>>) // Uses direct object if available
68    (Optional<?>)getBeanIfUnique(DataGenerator.class)
69    )
70    .or(() -> buildDataGeneratorByDataSource())
71    .or(() -> dataGenContext.getDefaultDataGenerator(testingInstance))
72    .orElseThrow(() -> new IllegalStateException(
73    String.format(
74    "Unable to find default DataGenerator from Spring context or auto-construction: [%s]",
75    nameOfTestingObject
76    )
77    ));
78    // :~)
79    }
80   
81  4 var genData = genDataInspector.genData();
82   
83  4 if (genData.generatorName().isEmpty()) {
84    /*
85    * Tries to get data generator from specified provider class
86    */
87  1 var providerClass = (Class<DataGeneratorProvider<TableFacet>>)genData.generator();
88   
89  1 return getBeanIfUnique(providerClass)
90    .map(providerBean -> (DataGenerator<TableFacet>)
91    ((DataGeneratorProvider<?>)providerBean).get()
92    )
93    .orElseGet(() -> dataGenContext.getTypedDataGenerator(providerClass, testingInstance));
94    // :~)
95    }
96   
97  3 return getBeanByName(genData.generatorName())
98    .map(foundBean -> {
99    /*
100    * Type checking for supported bean types
101    */
102  2 if (foundBean instanceof DataGeneratorProvider) {
103  1 return (DataGenerator<TableFacet>)((DataGeneratorProvider<?>)foundBean).get();
104    }
105   
106  1 if (foundBean instanceof DataGenerator) {
107  1 return (DataGenerator<TableFacet>)foundBean;
108    }
109    // :~)
110   
111  0 throw new BeanNotOfRequiredTypeException(
112    genData.generatorName(), DataGeneratorProvider.class, foundBean.getClass()
113    );
114    })
115    .orElseGet(() -> dataGenContext.getNamedDataGenerator(
116    genData.generatorName(), testingInstance
117    ));
118    }
119   
 
120  12 toggle @SuppressWarnings("unchecked")
121    @Override
122    public List<TableFacet> getTableFacets() throws Exception
123    {
124  12 var genData = genDataInspector.genData();
125   
126  12 if (genDataInspector.useDefaultTableFacets()) {
127    /*
128    * Tries to get the default data generator from Spring context first.
129    */
130  4 return getBeanIfUnique(
131    TableFacetsProvider.class
132    )
133    .map(providerBean -> (List<TableFacet>)providerBean.get())
134    .or(() -> (Optional<List<TableFacet>>)
135    (Optional<?>)getBeanIfUnique(List.class)
136    )
137    .or(() -> {
138  2 return dataGenContext.getDefaultTableFacets(testingInstance);
139    })
140    .get();
141    // :~)
142    }
143   
144  8 List<TableFacet> tableFacets = new ArrayList<>(genDataInspector.numberOfTableFacets());
145   
146  8 for (var classOfFacetsProvider: genData.value()) {
147  1 tableFacets.addAll(
148    getTableFacetsByProviderClass(
149    (Class<? extends TableFacetsProvider<TableFacet>>)classOfFacetsProvider,
150    testingInstance
151    )
152    );
153    }
154  8 for (var classOfFacetsProvider: genData.facets()) {
155  1 tableFacets.addAll(
156    getTableFacetsByProviderClass(
157    (Class<? extends TableFacetsProvider<TableFacet>>)classOfFacetsProvider,
158    testingInstance
159    )
160    );
161    }
162  8 for (var facetName: genData.facetsNames()) {
163  14 tableFacets.addAll(
164    getTableFacetsByName(
165    facetName, testingInstance
166    )
167    );
168    }
169   
170  8 return tableFacets;
171    }
172   
 
173  7 toggle @SuppressWarnings("unchecked")
174    private Optional<DataGenerator<TableFacet>> buildDataGeneratorByDataSource()
175    {
176  7 var dataSource = appContext.getBeanProvider(DataSource.class)
177    .getIfAvailable();
178   
179  7 if (dataSource == null) {
180  1 return Optional.empty();
181    }
182   
183  6 Object dataGeneratorObject;
184   
185  6 if (isActualTransactionActive()) {
186    /*
187    * Joins current transaction if it is active
188    */
189  4 logger.debug(
190    "Auto-constructing JdbcDataGenerator which joins current transaction for: {}",
191    nameOfTestingObject
192    );
193  4 dataGeneratorObject = (DataGenerator<TableFacet>)(Object)
194    new JdbcDataGenerator(DataSourceUtils.getConnection(dataSource));
195    // :~)
196    } else {
197  2 logger.debug(
198    "Auto-constructing JdbcDataGenerator by DataSource for: {}", dataSource
199    );
200  2 dataGeneratorObject = new JdbcDataGenerator(dataSource);
201    }
202   
203  6 return Optional.of(
204    (DataGenerator<TableFacet>)dataGeneratorObject
205    );
206    }
207   
 
208  14 toggle @SuppressWarnings("unchecked")
209    private List<TableFacet> getTableFacetsByName(String name, Object testingInstance)
210    {
211  14 return getBeanByName(name)
212    .<List<TableFacet>>map(foundBean -> {
213    /*
214    * Tries to use found bean to get table facets
215    */
216  12 if (foundBean instanceof TableFacetsProvider) {
217  3 return (List<TableFacet>)((TableFacetsProvider<?>)foundBean).get();
218    }
219   
220  9 if (foundBean instanceof TableFacet) {
221  2 return List.of((TableFacet)foundBean);
222    }
223   
224  7 if (foundBean instanceof List) {
225  2 return (List<TableFacet>)foundBean;
226    }
227   
228  5 if (foundBean instanceof Stream) {
229  2 return ((Stream<TableFacet>)foundBean).toList();
230    }
231   
232  3 var beanClass = foundBean.getClass();
233  3 if (beanClass.isArray() &&
234    TableFacet.class.isAssignableFrom(beanClass.getComponentType())
235    ) {
236  3 return Arrays.asList((TableFacet[])foundBean);
237    }
238    // :~)
239   
240  0 throw new BeanNotOfRequiredTypeException(
241    name, TableFacetsProvider.class, foundBean.getClass()
242    );
243    })
244    .orElseGet(() -> dataGenContext.getNamedTableFacets(
245    name, testingInstance
246    ));
247    }
248   
 
249  2 toggle @SuppressWarnings("unchecked")
250    private List<TableFacet> getTableFacetsByProviderClass(
251    Class<? extends TableFacetsProvider<TableFacet>> providerClass,
252    Object testingInstance
253    ) {
254  2 return getBeanIfUnique(providerClass)
255    .map(providerBean -> (List<TableFacet>)
256    ((TableFacetsProvider<?>)providerBean).get()
257    )
258    .orElseGet(() -> dataGenContext.getTypedTableFacets(
259    providerClass, testingInstance
260    ));
261    }
262   
 
263  26 toggle private <T> Optional<T> getBeanIfUnique(Class<T> beanClass)
264    {
265  26 try {
266  26 return Optional.of(appContext.getBean(beanClass));
267    } catch (NoUniqueBeanDefinitionException e) {
268  0 throw e;
269    } catch (NoSuchBeanDefinitionException e) {
270  19 logger.trace("Unable to find bean by type: \"{}\" in Spring context: [{}]",
271    beanClass.getName(), nameOfTestingObject);
272  19 return Optional.empty();
273    }
274    }
275   
 
276  17 toggle private Optional<Object> getBeanByName(String name)
277    {
278  17 try {
279  17 return Optional.of(appContext.getBean(name));
280    } catch (NoSuchBeanDefinitionException e) {
281  3 logger.trace("Unable to find bean by name: \"{}\" in Spring context: [{}]",
282    name, nameOfTestingObject);
283  3 return Optional.empty();
284    }
285    }
286    }