• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

leeonky / test-charm-java / 390

18 Oct 2025 04:40PM UTC coverage: 75.298% (+0.01%) from 75.288%
390

push

circleci

leeonky
refactor

8 of 8 new or added lines in 5 files covered. (100.0%)

19 existing lines in 8 files now uncovered.

8895 of 11813 relevant lines covered (75.3%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.89
/jfactory/src/main/java/com/github/leeonky/jfactory/ObjectProducer.java
1
package com.github.leeonky.jfactory;
2

3
import com.github.leeonky.util.BeanClass;
4
import com.github.leeonky.util.PropertyWriter;
5

6
import java.util.*;
7
import java.util.function.Function;
8
import java.util.stream.Collectors;
9

10
import static com.github.leeonky.jfactory.PropertyChain.propertyChain;
11
import static com.github.leeonky.util.function.Extension.getFirstPresent;
12
import static java.util.Optional.*;
13
import static java.util.stream.IntStream.range;
14

15
class ObjectProducer<T> extends Producer<T> {
16
    private final ObjectFactory<T> factory;
17
    private final JFactory jFactory;
18
    //    TODO refactor
19
    final DefaultBuilder<T> builder;
20
    private final boolean forQuery;
21
    private final ObjectInstance<T> instance;
22
    private final Map<String, Producer<?>> children = new HashMap<>();
1✔
23
    private final Map<PropertyChain, String> reverseAssociations = new LinkedHashMap<>();
1✔
24
    private final ListPersistable cachedChildren = new ListPersistable();
1✔
25
    private final Set<String> ignorePropertiesInSpec = new HashSet<>();
1✔
26
    private Persistable persistable;
27
    private Function<PropertyWriter<T>, Producer<?>> elementPopulationFactory = any -> null;
1✔
28
    private final ConsistencySet consistencySet = new ConsistencySet();
1✔
29
    private final List<PropertyStructureDependent> propertyStructureDependents = new ArrayList<>();
1✔
30
    private final List<DefaultListStructure<T, ?>> listStructures = new ArrayList<>();
1✔
31
    private boolean autoResolveBuilderValueProducer = false;
1✔
32

33
    public JFactory jFactory() {
34
        return jFactory;
1✔
35
    }
36

37
    public ObjectProducer(JFactory jFactory, ObjectFactory<T> factory, DefaultBuilder<T> builder,
38
                          Optional<Association> association, Optional<ReverseAssociation> reverseAssociation) {
39
        this(jFactory, factory, builder, false, association, reverseAssociation);
1✔
40
    }
1✔
41

42
    public ObjectProducer(JFactory jFactory, ObjectFactory<T> factory, DefaultBuilder<T> builder, boolean forQuery,
43
                          Optional<Association> association, Optional<ReverseAssociation> reverseAssociation) {
44
        super(factory.getType());
1✔
45
        this.factory = factory;
1✔
46
        this.jFactory = jFactory;
1✔
47
        this.builder = builder;
1✔
48
        this.forQuery = forQuery;
1✔
49
        instance = factory.createInstance(builder.getArguments(), association, reverseAssociation, this);
1✔
50
        persistable = jFactory.getDataRepository();
1✔
51
        createDefaultValueProducers();
1✔
52
        builder.collectSpec(this, instance);
1✔
53
        builder.processInputProperty(this, forQuery);
1✔
54
        resolveBuilderValueProducer(forQuery);
1✔
55
        instance.spec.applyPropertyStructureDefinitions(jFactory, this);
1✔
56
        processListStructures();
1✔
57
        setupReverseAssociations();
1✔
58

59
//        reverseAssociation.ifPresent(reverseAssociation1 -> {
60
//            reverseAssociations.forEach((r, a) -> {
61
//                if (reverseAssociation1.matches(a, getType().getPropertyWriter(r.toString()).getType().getElementOrPropertyType())) {
62
//                    if (descendantForRead(r) instanceof CollectionProducer) {
63
//                        changeDescendant(r.concat(0), (producer, s) -> reverseAssociation1.buildUnFixedValueProducer());
64
//                    } else
65
//                        changeDescendant(r, (producer, s) -> reverseAssociation1.buildUnFixedValueProducer());
66
//                }
67
//            });
68
//        });
69
    }
1✔
70

71
    private void processListStructures() {
72
        listStructures.forEach(listStructure -> listStructure.process(this, jFactory));
1✔
73
    }
1✔
74

75
    public Producer<?> newElementPopulationProducer(PropertyWriter<T> propertyWriter) {
76
        return getFirstPresent(() -> ofNullable(elementPopulationFactory.apply(propertyWriter)),
1✔
77
                () -> newDefaultValueProducer(propertyWriter))
1✔
78
                .orElseGet(() -> new DefaultTypeValueProducer<>(propertyWriter.getType()));
1✔
79
    }
80

81
    //        TODO refactor duplicated call
82
    @Override
83
    protected Producer<?> resolveBuilderValueProducer(boolean forQuery) {
84
        autoResolveBuilderValueProducer = true;
1✔
85
        for (Map.Entry<String, Producer<?>> kv : children.entrySet())
1✔
86
            setChild(kv.getKey(), kv.getValue());
1✔
87
        return this;
1✔
88
    }
89

90
    private void createElementDefaultValueProducersWhenBuildListAsRoot() {
91
        try {
92
            children.keySet().stream().map(Integer::valueOf).max(Integer::compareTo).ifPresent(size -> {
1✔
93
                size++;
1✔
94
                instance.setCollectionSize(size);
1✔
95
                range(0, size).mapToObj(String::valueOf)
1✔
96
                        .filter(index -> children.get(index) == null)
1✔
97
                        .map(index -> getType().getPropertyWriter(index))
1✔
98
                        .forEach((PropertyWriter<T> propertyWriter) ->
1✔
99
                                setChild(propertyWriter.getName(), newElementPopulationProducer(propertyWriter)));
1✔
100
            });
1✔
101
        } catch (Exception ignore) {
1✔
102
        }
1✔
103
    }
1✔
104

105
    private void setupReverseAssociations() {
106
        reverseAssociations.forEach((child, association) ->
1✔
107
                descendantForUpdate(child).setupAssociation(association, instance, cachedChildren));
1✔
108
    }
1✔
109

110
    @Override
111
    protected Producer<?> setChild(String property, Producer<?> producer) {
112
        if (autoResolveBuilderValueProducer)
1✔
113
            producer = producer.resolveBuilderValueProducer(forQuery);
1✔
114
        children.put(property, producer);
1✔
115
        return producer;
1✔
116
    }
117

118
    @Override
119
    public Optional<Producer<?>> getChild(String property) {
120
        return ofNullable(children.get(property));
1✔
121
    }
122

123
    @Override
124
    public Producer<?> childForUpdate(String property) {
125
        PropertyWriter<T> propertyWriter = getType().getPropertyWriter(property);
1✔
126
        return getFirstPresent(() -> getChild(propertyWriter.getName()),
1✔
127
                () -> newDefaultValueProducer(propertyWriter)).orElseGet(() -> {
1✔
128
            if (ignorePropertiesInSpec.contains(propertyWriter.getName()))
1✔
UNCOV
129
                return new ReadOnlyProducer<>(this, propertyWriter.getName());
×
130
            return new DefaultTypeValueProducer<>(propertyWriter.getType());
1✔
131
        });
132
    }
133

134
    @Override
135
    public Producer<?> childForRead(String property) {
136
        PropertyWriter<T> propertyWriter = getType().getPropertyWriter(property);
1✔
137
        return getFirstPresent(() -> getChild(propertyWriter.getName()),
1✔
138
                () -> newDefaultValueProducerForRead(propertyWriter)).orElseGet(() -> {
1✔
139
            if (ignorePropertiesInSpec.contains(propertyWriter.getName()))
1✔
140
                return new ReadOnlyProducer<>(this, propertyWriter.getName());
1✔
141
            return new DefaultTypeValueProducer<>(propertyWriter.getType());
1✔
142
        });
143
    }
144

145
    public Producer<?> forceChildOrDefaultCollection(PropertyWriter<T> propertyWriter) {
146
        return getChild(propertyWriter.getName()).orElseGet(() -> createCollectionProducer(propertyWriter));
1✔
147
    }
148

149
    @Override
150
    protected T produce() {
151
        return instance.cache(() -> {
1✔
152
            createElementDefaultValueProducersWhenBuildListAsRoot();
1✔
153
            return factory.create(instance);
1✔
154
        }, obj -> {
155
            produceSubs(obj);
1✔
156
            persistable.save(obj);
1✔
157
            cachedChildren.getAll().forEach(persistable::save);
1✔
158
        });
1✔
159
    }
160

161
    private void produceSubs(T obj) {
162
        children.entrySet().stream().filter(this::isDefaultValueProducer).forEach(e -> produceSub(obj, e));
1✔
163
        children.entrySet().stream().filter(e -> !(isDefaultValueProducer(e))).forEach(e -> produceSub(obj, e));
1✔
164
    }
1✔
165

166
    private void produceSub(T obj, Map.Entry<String, Producer<?>> e) {
167
        getType().setPropertyValue(obj, e.getKey(), e.getValue().getValue());
1✔
168
    }
1✔
169

170
    private boolean isDefaultValueProducer(Map.Entry<String, Producer<?>> e) {
171
        return e.getValue() instanceof DefaultValueFactoryProducer;
1✔
172
    }
173

174
    public ObjectProducer<T> processConsistent() {
175
        collectConsistent(this, propertyChain(""));
1✔
176
        consistencySet.resolve(this);
1✔
177
        return this;
1✔
178
    }
179

180
    @Override
181
    public void verifyPropertyStructureDependent() {
182
        for (PropertyStructureDependent propertyStructureDependent : propertyStructureDependents)
1✔
183
            propertyStructureDependent.verify(getValue());
1✔
184
        children.values().forEach(Producer::verifyPropertyStructureDependent);
1✔
185
    }
1✔
186

187
    @Override
188
    protected void collectConsistent(ObjectProducer<?> root, PropertyChain base) {
189
        if (root != this)
1✔
190
            root.consistencySet.addAll(consistencySet.absoluteProperty(base));
1✔
191
        children.forEach((property, producer) -> producer.collectConsistent(root, base.concat(property)));
1✔
192
    }
1✔
193

194
    private void createDefaultValueProducers() {
195
        getType().getPropertyWriters().values().stream().filter(jFactory::shouldCreateDefaultValue)
1✔
196
                .forEach(propertyWriter -> factory.getFactorySet().newDefaultValueFactoryProducer(propertyWriter, instance.sub(propertyWriter))
1✔
197
                        .ifPresent(producer -> setChild(propertyWriter.getName(), producer)));
1✔
198
    }
1✔
199

200
    @Override
201
    public Optional<Producer<?>> newDefaultValueProducer(PropertyWriter<T> property) {
202
        if (ignorePropertiesInSpec.contains(property.getName()))
1✔
UNCOV
203
            return empty();
×
204
        if (property.getType().isCollection()) {
1✔
205
            return of(createCollectionProducer(property));
1✔
206
        } else
207
            return factory.getFactorySet().newDefaultValueFactoryProducer(property, instance.sub(property));
1✔
208
    }
209

210
    public Optional<Producer<?>> newDefaultValueProducerForRead(PropertyWriter<T> property) {
211
        if (ignorePropertiesInSpec.contains(property.getName()))
1✔
212
            return empty();
1✔
213
        else
214
            return factory.getFactorySet().newDefaultValueFactoryProducer(property, instance.sub(property));
1✔
215
    }
216

217
    private Producer<?> createCollectionProducer(PropertyWriter<T> property) {
218
        return setChild(property.getName(), new CollectionProducer<>(getType(), property.getType(), instance.sub(property),
1✔
219
                factory.getFactorySet(), jFactory));
1✔
220
    }
221

222
    @Override
223
    public Producer<T> changeTo(Producer<T> newProducer) {
224
        return newProducer.changeFrom(this);
1✔
225
    }
226

227
    public void appendReverseAssociation(PropertyChain property, String association) {
228
        reverseAssociations.put(property, association);
1✔
229
    }
1✔
230

231
    @Override
232
    protected <R> void setupAssociation(String association, ObjectInstance<R> instance, ListPersistable cachedChildren) {
233
        setChild(association, new UnFixedValueProducer<>(instance.reference(), instance.spec().getType()));
1✔
234
        persistable = cachedChildren;
1✔
235
    }
1✔
236

237
    public boolean isReverseAssociation(String property) {
238
        return reverseAssociations.containsKey(PropertyChain.propertyChain(property));
1✔
239
    }
240

241
    public void ignoreProperty(String property) {
242
        ignorePropertiesInSpec.add(property);
1✔
243
    }
1✔
244

245
    public void processSpecIgnoreProperties() {
246
        children.entrySet().stream().filter(e -> e.getValue() instanceof DefaultValueProducer
1✔
247
                        && ignorePropertiesInSpec.contains(e.getKey())).map(Map.Entry::getKey).collect(Collectors.toList())
1✔
248
                .forEach(children::remove);
1✔
249
    }
1✔
250

251
    @Override
252
    protected boolean isFixed() {
253
        return children.values().stream().anyMatch(Producer::isFixed);
1✔
254
    }
255

256
    public void changeElementPopulationFactory(Function<PropertyWriter<T>, Producer<?>> factory) {
257
        elementPopulationFactory = factory;
1✔
258
    }
1✔
259

260
    public void appendLink(DefaultConsistency<?, ?> consistency) {
261
        consistencySet.add(consistency);
1✔
262
    }
1✔
263

264
    public void lock(PropertyStructureDependent propertyStructureDependent) {
265
        propertyStructureDependents.add(propertyStructureDependent);
1✔
266
    }
1✔
267

268
    public void appendListStructure(DefaultListStructure<T, ?> listStructure) {
269
        listStructures.add(listStructure);
1✔
270
    }
1✔
271

272
    public Optional<Association> association(String string) {
273
        return ofNullable(reverseAssociations.get(propertyChain(string)))
1✔
274
                .map(p -> new Association(p));
1✔
275
    }
276

277
    public Optional<String> reverseAssociation(PropertyChain property) {
278
        return Optional.ofNullable(reverseAssociations.get(property));
1✔
279
    }
280
}
281

282
//TODO refactor
283
class Association {
284
    final String property;
285

286
    Association(String property) {
1✔
287
        this.property = property;
1✔
288
    }
1✔
289

290
    boolean matches(String property) {
291
        return this.property.equals(property);
1✔
292
    }
293
}
294

295
class ReverseAssociation {
296
    private final String property;
297
    //    TODO refactor
298
    final Instance<?> instance;
299

300
    ReverseAssociation(String property, Instance<?> instance) {
1✔
301
        this.property = property;
1✔
302
        this.instance = instance;
1✔
303
    }
1✔
304

305
    public boolean matches(String property, BeanClass<?> type) {
306
        return this.property.equals(property) && instance.spec().getType().equals(type);
1✔
307
    }
308

309
    UnFixedValueProducer buildUnFixedValueProducer() {
UNCOV
310
        return new UnFixedValueProducer(instance.reference(), instance.spec().getType());
×
311
    }
312
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc