Skip to content

Commit 27b968f

Browse files
authored
Merge pull request #47 from bowbahdoe/cleanup-march-1
Add json Encoder and bump version
2 parents d856332 + 7e1f0a3 commit 27b968f

File tree

5 files changed

+182
-3
lines changed

5 files changed

+182
-3
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ Requires Java 17+.
1616
<dependency>
1717
<groupId>dev.mccue</groupId>
1818
<artifactId>json</artifactId>
19-
<version>0.2.2</version>
19+
<version>0.2.3</version>
2020
</dependency>
2121
```
2222

2323
### Gradle
2424

2525
```
2626
dependencies {
27-
implementation("dev.mccue:json:0.2.2")
27+
implementation("dev.mccue:json:0.2.3")
2828
}
2929
```
3030

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>dev.mccue</groupId>
88
<artifactId>json</artifactId>
9-
<version>0.2.2</version>
9+
<version>0.2.3</version>
1010
<packaging>jar</packaging>
1111

1212
<properties>

src/main/java/dev/mccue/json/Json.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,41 @@ static Json of(Collection<? extends JsonEncodable> value) {
239239
);
240240
}
241241

242+
/**
243+
* Creates {@link Json} from a {@link Collection} of items which
244+
* can be encoded with a provided {@link JsonEncoder}.
245+
*
246+
* @param value The value to be encoded.
247+
* @return An instance of {@link Json}.
248+
*/
249+
static <T> Json of(Collection<? extends T> value, JsonEncoder<T> encoder) {
250+
return value == null
251+
? JsonNull.instance()
252+
: new ArrayImpl(
253+
value.stream()
254+
.map(v -> {
255+
var result = encoder.encode(v);
256+
if (result == null) {
257+
return JsonNull.instance();
258+
}
259+
else {
260+
return result;
261+
}
262+
})
263+
.toList()
264+
);
265+
}
266+
267+
242268
/**
243269
* Creates {@link Json} from a {@link Map} with {@link String} keys to values which
244270
* implement {@link JsonEncodable}.
245271
*
272+
* <p>
273+
* Note that this method is null-safe when provided a null container,
274+
* but only null-safe for map values if the provided encoder also is.
275+
* </p>
276+
*
246277
* @param value The value to be encoded.
247278
* @return An instance of {@link Json}.
248279
*/
@@ -262,6 +293,40 @@ static Json of(Map<String, ? extends JsonEncodable> value) {
262293
);
263294
}
264295

296+
/**
297+
* Creates {@link Json} from a {@link Map} with {@link String} keys to values which
298+
* can be encoded with a provided {@link JsonEncoder}.
299+
*
300+
* <p>
301+
* Note that this method is null-safe when provided a null container,
302+
* but only null-safe for map values if the provided encoder also is.
303+
* </p>
304+
*
305+
* @param value The value to be encoded.
306+
* @return An instance of {@link Json}.
307+
*/
308+
static <T> Json of(Map<String, ? extends T> value, JsonEncoder<T> encoder) {
309+
return value == null
310+
? JsonNull.instance()
311+
: new ObjectImpl(
312+
value
313+
.entrySet()
314+
.stream()
315+
.collect(Collectors.toUnmodifiableMap(
316+
Map.Entry::getKey,
317+
entry -> {
318+
var result = encoder.encode(entry.getValue());
319+
if (result == null) {
320+
return JsonNull.instance();
321+
}
322+
else {
323+
return result;
324+
}
325+
}
326+
))
327+
);
328+
}
329+
265330
/**
266331
* Creates a new {@link JsonObject.Builder}.
267332
*
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package dev.mccue.json;
2+
3+
import java.util.function.Function;
4+
5+
/**
6+
* Object that knows how to encode an object into Json.
7+
*
8+
* <p>
9+
* This is a counterpart to {@link JsonEncodable} which can be provided
10+
* to encode objects in contexts where elements are not, for whatever reason,
11+
* have an intrinsic Json representation.
12+
* </p>
13+
* @param <T> The type of element to encode.
14+
*/
15+
public interface JsonEncoder<T> {
16+
/**
17+
* Encodes the given value to Json.
18+
* @param value The value to encode.
19+
* @return The encoded value.
20+
*/
21+
Json encode(T value);
22+
23+
24+
/**
25+
* Creates a {@link JsonEncoder} which delegates to an intrinsic implementation
26+
* provided by virtue of being {@link JsonEncodable}.
27+
* @return A {@link JsonEncoder}.
28+
* @param <T> The type to encode.
29+
*/
30+
static <T extends JsonEncodable> JsonEncoder<T> of() {
31+
return JsonEncodable::toJson;
32+
}
33+
34+
/**
35+
* Convenience method to target a lambda expression to a {@link JsonEncoder}
36+
* and be able to call methods such as {@link JsonEncoder#map(Function)}.
37+
* @param encoder The expression to wrap as an encoder.
38+
* @return A {@link JsonEncoder}.
39+
* @param <T> The type to encode.
40+
*/
41+
static <T> JsonEncoder<T> of(JsonEncoder<? super T> encoder) {
42+
return encoder::encode;
43+
}
44+
45+
/**
46+
* Maps the result of this encoder.
47+
* @param f The function to apply.
48+
* @return An encoder that encodes a different type.
49+
* @param <R> The type the returned encoder will encode.
50+
*/
51+
default <R> JsonEncoder<R> map(Function<? super R, ? extends T> f) {
52+
return r -> this.encode(f.apply(r));
53+
}
54+
}

src/test/java/dev/mccue/json/JsonTest.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
import java.math.BigDecimal;
66
import java.math.BigInteger;
7+
import java.util.ArrayList;
8+
import java.util.HashMap;
79
import java.util.List;
810
import java.util.Map;
911

@@ -34,6 +36,64 @@ public void testOfCollection() {
3436
JsonArray.of(Json.ofFalse(), Json.of(1), Json.of("abc")),
3537
Json.of(List.of((JsonEncodable) Json::ofFalse, Json.of(1), Json.of("abc")))
3638
);
39+
40+
var l = new ArrayList<Json>();
41+
l.add(null);
42+
assertEquals(
43+
JsonArray.of(JsonNull.instance()),
44+
Json.of(l)
45+
);
46+
}
47+
48+
@Test
49+
public void testOfCollectionEncodable() {
50+
assertEquals(
51+
JsonArray.of(Json.ofFalse()),
52+
Json.of(List.of(false), JsonBoolean::of)
53+
);
54+
55+
assertEquals(
56+
JsonArray.of(Json.ofNull()),
57+
Json.of(List.of(false), __ -> null)
58+
);
59+
60+
assertEquals(
61+
JsonArray.of(Json.ofNull()),
62+
Json.of(List.of(false), __ -> JsonNull.instance())
63+
);
64+
}
65+
66+
@Test
67+
public void testOfMap() {
68+
var m = new HashMap<String, JsonEncodable>();
69+
m.put("a", null);
70+
m.put("b", Json.of(1));
71+
72+
assertEquals(
73+
JsonObject.of(Map.of(
74+
"a", JsonNull.instance(),
75+
"b", Json.of(1)
76+
)),
77+
Json.of(m)
78+
);
79+
}
80+
81+
@Test
82+
public void testOfMapEncoder() {
83+
var m = new HashMap<String, Integer>();
84+
m.put("a", 6);
85+
m.put("b", 7);
86+
87+
m.put("c", null);
88+
89+
assertEquals(
90+
JsonObject.of(Map.of(
91+
"a", Json.of(6),
92+
"b", Json.of(7),
93+
"c", JsonNull.instance()
94+
)),
95+
Json.of(m, Json::of)
96+
);
3797
}
3898

3999
@Test

0 commit comments

Comments
 (0)