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

leeonky / test-charm-java / 368

12 Oct 2025 01:55PM UTC coverage: 75.301% (+0.1%) from 75.185%
368

push

circleci

leeonky
one to many

13 of 13 new or added lines in 2 files covered. (100.0%)

10 existing lines in 4 files now uncovered.

8893 of 11810 relevant lines covered (75.3%)

0.75 hits per line

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

97.64
/jfactory/src/main/java/com/github/leeonky/jfactory/PropertySpec.java
1
package com.github.leeonky.jfactory;
2

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

7
import java.util.List;
8
import java.util.Optional;
9
import java.util.function.Consumer;
10
import java.util.function.Function;
11
import java.util.function.Supplier;
12

13
import static com.github.leeonky.util.Sneaky.cast;
14
import static java.lang.String.format;
15
import static java.util.Optional.of;
16

17
public class PropertySpec<T> {
18
    private final Spec<T> spec;
19
    private final PropertyChain property;
20

21
    PropertySpec(Spec<T> spec, PropertyChain property) {
1✔
22
        this.spec = spec;
1✔
23
        this.property = property;
1✔
24
    }
1✔
25

26
    public Spec<T> value(Object value) {
27
        return value(() -> value);
1✔
28
    }
29

30
    @SuppressWarnings("unchecked")
31
    public <V> Spec<T> value(Supplier<V> value) {
32
        if (value == null)
1✔
33
            return value(() -> null);
1✔
34
        return appendProducer(context ->
1✔
35
                new UnFixedValueProducer<>(value, (BeanClass<V>) context.producer.getPropertyWriterType(context.property)));
1✔
36
    }
37

38
    @Deprecated
39
    /**
40
     * reference spec and trait via string
41
     */
42
    public <V> Spec<T> is(Class<? extends Spec<V>> specClass) {
43
        if (isAssociation())
1✔
44
            return spec;
1✔
45
        return appendProducer(context -> createCreateProducer(context.jFactory.spec(specClass), context.association));
1✔
46
    }
47

48
    private boolean isAssociation() {
49
        return spec.isAssociation(property.toString()) || spec.isReverseAssociation(property.removeTail());
1✔
50
    }
51

52
    public Spec<T> is(String... traitsAndSpec) {
53
        if (isAssociation())
1✔
54
            return spec;
1✔
55
        return appendProducer(context -> createCreateProducer(context.jFactory.spec(traitsAndSpec), context.association));
1✔
56
    }
57

58
    public <V> IsSpec2<V> from(String... traitsAndSpec) {
59
        return spec.newIsSpec(traitsAndSpec, this);
1✔
60
    }
61

62
    public Spec<T> optional(String... traitsAndSpec) {
63
        if (property.isSingle()) {
1✔
64
            return spec.appendSpec((jFactory, objectProducer) -> objectProducer.changeChild(property.toString(),
1✔
65
                    new OptionalSpecDefaultValueProducer<>(objectProducer.getPropertyWriterType(property.toString()), traitsAndSpec)));
1✔
66
        } else if (property.isDefaultPropertyCollection()) {
1✔
67
            return spec.appendSpec((jFactory, objectProducer) -> {
1✔
68
                PropertyWriter<T> propertyWriter = objectProducer.getType().getPropertyWriter((String) property.head());
1✔
69
                if (!propertyWriter.getType().isCollection() && propertyWriter.getType().is(Object.class)) {
1✔
70
                    Factory<Object> factory = jFactory.specFactory(traitsAndSpec[traitsAndSpec.length - 1]);
1✔
71
                    propertyWriter = propertyWriter.decorateType(GenericBeanClass.create(List.class, factory.getType().getGenericType()));
1✔
72
                } else if (propertyWriter.getType().isCollection() && propertyWriter.getType().getElementType().is(Object.class)) {
1✔
73
                    Factory<Object> factory = jFactory.specFactory(traitsAndSpec[traitsAndSpec.length - 1]);
1✔
74
                    propertyWriter = propertyWriter.decorateType(GenericBeanClass.create(propertyWriter.getType().getType(), factory.getType().getGenericType()));
1✔
75
                }
76
                CollectionProducer<?, ?> collectionProducer = BeanClass.cast(objectProducer.forceChildOrDefaultCollection(propertyWriter),
1✔
77
                        CollectionProducer.class).orElseThrow(() ->
1✔
UNCOV
78
                        new IllegalArgumentException(format("%s.%s is not list", spec.getType().getName(), property.head())));
×
79
                OptionalSpecDefaultValueProducer<?> optionalSpecDefaultValueProducer =
1✔
80
                        new OptionalSpecDefaultValueProducer<>(propertyWriter.getType(), traitsAndSpec);
1✔
81
                collectionProducer.changeElementPopulationFactory(index -> optionalSpecDefaultValueProducer);
1✔
82
            });
1✔
83
        }
UNCOV
84
        throw new IllegalArgumentException(format("Not support property chain '%s' in current operation", property));
×
85
    }
86

87
    @Deprecated
88
    /**
89
     * reference spec and trait via string
90
     */
91
    public <V, S extends Spec<V>> IsSpec<V, S> from(Class<S> specClass) {
92
        return spec.newIsSpec(specClass, this);
1✔
93
    }
94

95
    public Spec<T> defaultValue(Object value) {
96
        return defaultValue(() -> value);
1✔
97
    }
98

99
    @SuppressWarnings("unchecked")
100
    public <V> Spec<T> defaultValue(Supplier<V> supplier) {
101
        if (supplier == null)
1✔
UNCOV
102
            return defaultValue((Object) null);
×
103
        return appendProducer((context) ->
1✔
104
                new DefaultValueProducer<>((BeanClass<V>) context.producer.getPropertyWriterType(context.property), supplier));
1✔
105
    }
106

107
    public Spec<T> byFactory() {
108
        if (isAssociation())
1✔
109
            return spec;
1✔
110
        return appendProducer(context ->
1✔
111
                context.producer.newDefaultValueProducer(cast(context.producer.getType().getPropertyWriter(context.property))).orElseGet(() ->
1✔
112
                        createCreateProducer(context.jFactory.type(context.producer.getPropertyWriterType(context.property).getType()), context.association)));
1✔
113
    }
114

115
    public Spec<T> byFactory(Function<Builder<?>, Builder<?>> builder) {
116
        if (isAssociation())
1✔
117
            return spec;
1✔
118
        return appendProducer(context ->
1✔
119
                context.producer.newDefaultValueProducer(cast(context.producer.getType().getPropertyWriter(context.property))).orElseGet(() ->
1✔
120
                        createQueryOrCreateProducer(builder.apply(context.jFactory.type(
1✔
121
                                context.producer.getPropertyWriterType(context.property).getType())))));
1✔
122
    }
123

124
    public Spec<T> dependsOn(String dependency) {
125
        spec.consistent(Object.class)
1✔
126
                .property(property.toString()).write(Function.identity())
1✔
127
                .property(dependency).read(Function.identity());
1✔
128
        return spec;
1✔
129
    }
130

131
    public Spec<T> dependsOn(String dependency, Function<Object, Object> rule) {
132
        spec.consistent(Object.class)
1✔
133
                .property(property.toString()).write(Function.identity())
1✔
134
                .property(dependency).read(rule);
1✔
135
        return spec;
1✔
136
    }
137

138
    public Spec<T> dependsOn(List<String> dependencies, Function<Object[], Object> rule) {
139
        spec.consistent(Object.class)
1✔
140
                .property(property.toString()).write(Function.identity())
1✔
141
                .properties(dependencies.toArray(new String[0])).read(rule);
1✔
142
        return spec;
1✔
143
    }
144

145
    private Spec<T> appendProducer(Function<ProducerFactoryContext, Producer<?>> producerFactory) {
146
        if (property.isSingle() || property.isTopLevelPropertyCollection())
1✔
147
            return spec.appendSpec((jFactory, objectProducer) -> objectProducer.changeDescendant(property,
1✔
148
                    ((nextToLast, property) -> producerFactory.apply(new ProducerFactoryContext(jFactory, nextToLast, property,
1✔
149
                            objectProducer.association(this.property.head().toString()), objectProducer)))));
1✔
150
        if (property.isDefaultPropertyCollection()) {
1✔
151
            return spec.appendSpec((jFactory, objectProducer) -> {
1✔
152
                PropertyWriter<T> propertyWriter = objectProducer.getType().getPropertyWriter((String) property.head());
1✔
153
                if (!propertyWriter.getType().isCollection() && propertyWriter.getType().is(Object.class)) {
1✔
154
                    Producer<?> element = producerFactory.apply(new ProducerFactoryContext(jFactory, objectProducer, "0", objectProducer.association(property.head().toString()), objectProducer));
1✔
155
                    propertyWriter = propertyWriter.decorateType(GenericBeanClass.create(List.class, element.getType().getGenericType()));
1✔
156
                }
157
                CollectionProducer<?, ?> collectionProducer = BeanClass.cast(objectProducer.forceChildOrDefaultCollection(propertyWriter),
1✔
158
                        CollectionProducer.class).orElseThrow(() ->
1✔
159
                        new IllegalArgumentException(format("%s.%s is not list", spec.getType().getName(), property.head())));
1✔
160
                collectionProducer.changeElementPopulationFactory(index ->
1✔
161
                        producerFactory.apply(new ProducerFactoryContext(jFactory, collectionProducer, index.getName(), objectProducer.association(property.head().toString()), objectProducer)));
1✔
162
            });
1✔
163
        }
164
        if (property.isTopLevelDefaultPropertyCollection()) {
1✔
165
            return spec.appendSpec((jFactory, objectProducer) -> {
1✔
166
                objectProducer.changeElementPopulationFactory(propertyWriter ->
1✔
167
                        producerFactory.apply(new ProducerFactoryContext(jFactory, objectProducer, propertyWriter.getName(), Optional.empty(), objectProducer)));
1✔
168
            });
1✔
169
        }
170
        throw new IllegalArgumentException(format("Not support property chain '%s' in current operation", property));
1✔
171
    }
172

173
    @SuppressWarnings("unchecked")
174
    private <V> Producer<V> createQueryOrCreateProducer(Builder<V> builder) {
175
        Builder<V> builderWithArgs = builder.args(spec.params(property.toString()));
1✔
176
        return builderWithArgs.queryAll().stream().findFirst().<Producer<V>>map(object ->
1✔
177
                        new BuilderValueProducer<>((BeanClass<V>) BeanClass.create(object.getClass()), builderWithArgs))
1✔
178
                .orElseGet(builderWithArgs::createProducer);
1✔
179
    }
180

181
    private <V> Producer<V> createCreateProducer(Builder<V> builder, Optional<Association> association) {
182
        return builder.args(spec.params(property.toString())).createProducer(association,
1✔
183
                of(new ReverseAssociation(property.toString(), spec.instance())));
1✔
184
    }
185

186
    public Spec<T> reverseAssociation(String association) {
187
        spec.objectProducer.appendReverseAssociation(property, association);
1✔
188
        return spec;
1✔
189
    }
190

191
    public Spec<T> ignore() {
192
        return spec.appendSpec((jFactory, objectProducer) -> objectProducer.ignoreProperty(property.toString()));
1✔
193
    }
194

195
    public PropertySpec<T> element(int index) {
196
        return spec.property(property.toString() + "[" + index + "]");
1✔
197
    }
198

199
    @FunctionalInterface
200
    interface Fuc<P1, P2, P3, P4, R> {
201
        R apply(P1 p1, P2 p2, P3 p3, P4 p4);
202
    }
203

204
    public class IsSpec<V, S extends Spec<V>> {
205
        private final Class<S> specClass;
206
        private final String position;
207

208
        public IsSpec(Class<S> spec) {
1✔
209
            position = Thread.currentThread().getStackTrace()[4].toString();
1✔
210
            specClass = spec;
1✔
211
        }
1✔
212

213
        public Spec<T> which(Consumer<S> trait) {
214
            spec.consume(this);
1✔
215
            if (isAssociation())
1✔
216
                return spec;
1✔
217
            return appendProducer(context -> createCreateProducer(context.jFactory.spec(specClass, trait), context.association));
1✔
218
        }
219

220
        public Spec<T> and(Function<Builder<V>, Builder<V>> builder) {
221
            spec.consume(this);
1✔
222
            if (isAssociation())
1✔
223
                return spec;
1✔
224
            return appendProducer(context -> createQueryOrCreateProducer(builder.apply(context.jFactory.spec(specClass))));
1✔
225
        }
226

227
        public String getPosition() {
228
            return position;
1✔
229
        }
230
    }
231

232
    public class IsSpec2<V> {
233
        private final String[] spec;
234
        private final String position;
235

236
        public IsSpec2(String[] spec) {
1✔
237
            position = Thread.currentThread().getStackTrace()[4].toString();
1✔
238
            this.spec = spec;
1✔
239
        }
1✔
240

241
        public Spec<T> and(Function<Builder<V>, Builder<V>> builder) {
242
            PropertySpec.this.spec.consume(this);
1✔
243
            if (isAssociation())
1✔
244
                return PropertySpec.this.spec;
1✔
245
            return appendProducer(context -> createQueryOrCreateProducer(builder.apply(context.jFactory.spec(spec))));
1✔
246
        }
247

248
        public String getPosition() {
249
            return position;
1✔
250
        }
251
    }
252
}
253

254
class ProducerFactoryContext {
255
    final JFactory jFactory;
256
    final Producer<?> producer;
257
    final String property;
258
    final Optional<Association> association;
259
    final ObjectProducer<?> objectProducer;
260

261
    ProducerFactoryContext(JFactory jFactory, Producer<?> producer,
262
                           String property, Optional<Association> association,
263
                           ObjectProducer<?> objectProducer) {
1✔
264
        this.jFactory = jFactory;
1✔
265
        this.producer = producer;
1✔
266
        this.property = property;
1✔
267
        this.association = association;
1✔
268
        this.objectProducer = objectProducer;
1✔
269
    }
1✔
270
}
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