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

trydofor / professional-wings / #133

28 Jan 2025 03:45AM UTC coverage: 63.721% (+0.2%) from 63.497%
#133

push

trydofor
🐍 happy lunar snake year #308

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

129 existing lines in 8 files now uncovered.

12973 of 20359 relevant lines covered (63.72%)

0.64 hits per line

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

80.6
/wings/slardar/src/main/java/pro/fessional/wings/slardar/jackson/EmptyValuePropertyFilter.java
1
package pro.fessional.wings.slardar.jackson;
2

3
import com.fasterxml.jackson.annotation.JsonFilter;
4
import com.fasterxml.jackson.core.JsonGenerator;
5
import com.fasterxml.jackson.databind.JavaType;
6
import com.fasterxml.jackson.databind.SerializerProvider;
7
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
8
import com.fasterxml.jackson.databind.ser.PropertyWriter;
9
import lombok.extern.slf4j.Slf4j;
10
import org.jetbrains.annotations.Nullable;
11
import pro.fessional.mirana.time.ThreadNow;
12

13
import java.lang.reflect.Array;
14
import java.time.LocalDate;
15
import java.time.LocalDateTime;
16
import java.time.OffsetDateTime;
17
import java.time.ZonedDateTime;
18
import java.util.Collection;
19
import java.util.Date;
20
import java.util.Map;
21

22
/**
23
 * <pre>
24
 * no output if LocalDate, LocalDateTime, ZonedDateTime or OffsetDateTime is `empty`.
25
 * no output if Array, Collection or Map is `empty`.
26
 * </pre>
27
 *
28
 * @author trydofor
29
 * @since 2021-10-28
30
 */
31
@Slf4j
1✔
32
public class EmptyValuePropertyFilter implements AutoRegisterPropertyFilter {
33

34
    public static final String Id = "EmptyValue";
35

36
    @JsonFilter(Id)
37
    public static class EmptyValueMixin {
×
38
    }
39
    public static final Class<?> MixinClass = Object.class;
1✔
40

41
    private final LocalDate emptyDate;
42
    private final LocalDateTime emptyDateMin;
43
    private final LocalDateTime emptyDateMax;
44
    private final boolean emptyList;
45
    private final boolean emptyMap;
46

47
    public EmptyValuePropertyFilter(@Nullable LocalDate emptyDate, int offset, boolean list, boolean map) {
1✔
48
        this.emptyDate = emptyDate;
1✔
49
        if (emptyDate != null) {
1✔
50
            final LocalDateTime dt = emptyDate.atStartOfDay();
1✔
51
            if (offset != 0) {
1✔
52
                this.emptyDateMin = dt.minusHours(offset);
1✔
53
                this.emptyDateMax = dt.plusHours(offset);
1✔
54
            }
55
            else {
56
                this.emptyDateMin = null;
×
UNCOV
57
                this.emptyDateMax = null;
×
58
            }
59
        }
1✔
60
        else {
61
            this.emptyDateMin = null;
×
UNCOV
62
            this.emptyDateMax = null;
×
63
        }
64
        this.emptyList = list;
1✔
65
        this.emptyMap = map;
1✔
66
    }
1✔
67

68
    @Override
69
    public String getId() {
70
        return Id;
1✔
71
    }
72

73
    @Override
74
    public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider prov, PropertyWriter writer) throws Exception {
75
        final JavaType rt = writer.getType();
1✔
76
        if (writer instanceof BeanPropertyWriter) {
1✔
77
            try {
78
                BeanPropertyWriter wt = (BeanPropertyWriter) writer;
1✔
79
                if ((emptyDate != null && dealEmptyDate(pojo, gen, prov, wt, rt)) ||
1✔
80
                    (emptyList && dealEmptyList(pojo, gen, prov, wt, rt)) ||
1✔
81
                    (emptyMap && dealEmptyMap(pojo, gen, prov, wt, rt))) {
1✔
82
                    return;
1✔
83
                }
84
            }
85
            catch (Exception ex) {
×
UNCOV
86
                if (log.isDebugEnabled()) {
×
87
                    // noinspection StringConcatenationArgumentToLogCall
UNCOV
88
                    log.debug("Skipping '" + writer.getFullName() + "' on '" + pojo.getClass().getName()
×
89
                              + "' as an exception was thrown when retrieving its value", ex);
90
                }
91
            }
1✔
92
        }
93
        writer.serializeAsField(pojo, gen, prov);
1✔
94
    }
1✔
95

96
    private boolean dealEmptyList(Object pojo, JsonGenerator gen, SerializerProvider prov, BeanPropertyWriter writer, JavaType rt) throws Exception {
97
        final boolean isArr = rt.isArrayType();
1✔
98
        if ((isArr || rt.isTypeOrSubTypeOf(Collection.class))) {
1✔
99
            final Object v = writer.get(pojo);
1✔
100
            if ((v instanceof Collection && ((Collection<?>) v).isEmpty()) ||
1✔
101
                (isArr && v != null && Array.getLength(v) == 0)) {
1✔
102
                return skipEmpty(pojo, gen, prov, writer);
1✔
103
            }
104
        }
105

106
        return false;
1✔
107
    }
108

109
    private boolean dealEmptyMap(Object pojo, JsonGenerator gen, SerializerProvider prov, BeanPropertyWriter writer, JavaType rt) throws Exception {
110
        if (rt.isTypeOrSubTypeOf(Map.class)) {
1✔
111
            final Object v = writer.get(pojo);
1✔
112
            if (v instanceof Map && ((Map<?, ?>) v).isEmpty()) {
1✔
113
                return skipEmpty(pojo, gen, prov, writer);
1✔
114
            }
115
        }
116
        return false;
1✔
117
    }
118

119
    private boolean dealEmptyDate(Object pojo, JsonGenerator gen, SerializerProvider prov, BeanPropertyWriter writer, JavaType rt) throws Exception {
120
        if ((rt.isTypeOrSubTypeOf(LocalDate.class) ||
1✔
121
             rt.isTypeOrSubTypeOf(LocalDateTime.class) ||
1✔
122
             rt.isTypeOrSubTypeOf(ZonedDateTime.class) ||
1✔
123
             rt.isTypeOrSubTypeOf(OffsetDateTime.class) ||
1✔
124
             rt.isTypeOrSubTypeOf(Date.class))
1✔
125
        ) {
126
            final Object v = writer.get(pojo);
1✔
127
            if ((v instanceof LocalDate && emptyDate((LocalDate) v)) ||
1✔
128
                (v instanceof LocalDateTime && emptyDateTime((LocalDateTime) v)) ||
1✔
129
                (v instanceof ZonedDateTime && emptyDateTime(((ZonedDateTime) v).toLocalDateTime())) ||
1✔
130
                (v instanceof OffsetDateTime && emptyDateTime(((OffsetDateTime) v).toLocalDateTime())) ||
1✔
UNCOV
131
                (v instanceof Date && emptyDateTime((Date) v))
×
132
            ) {
133
                return skipEmpty(pojo, gen, prov, writer);
1✔
134
            }
135
        }
136
        return false;
1✔
137
    }
138

139
    private boolean emptyDate(LocalDate d) {
140
        return emptyDate.equals(d);
1✔
141
    }
142

143
    private boolean emptyDateTime(Date dt) {
144
        final LocalDateTime ldt = dt.toInstant().atZone(ThreadNow.sysZoneId()).toLocalDateTime();
×
UNCOV
145
        return emptyDateTime(ldt);
×
146
    }
147

148
    // Considering timezone, the difference is considered equal within `offset` hours.
149
    private boolean emptyDateTime(LocalDateTime dt) {
150
        if (emptyDate.equals(dt.toLocalDate())) return true;
1✔
151
        if (emptyDateMin == null || emptyDateMax == null) {
1✔
UNCOV
152
            return false;
×
153
        }
154
        else {
155
            return !dt.isBefore(emptyDateMin) && !dt.isAfter(emptyDateMax);
1✔
156
        }
157
    }
158

159
    private boolean skipEmpty(Object pojo, JsonGenerator gen, SerializerProvider prov, BeanPropertyWriter writer) throws Exception {
160
        if (!gen.canOmitFields()) {
1✔
UNCOV
161
            writer.serializeAsOmittedField(pojo, gen, prov);
×
162
        }
163
        return true;
1✔
164
    }
165
}
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