Skip to content

Commit eb9e7e0

Browse files
authored
Merge branch 'avaje:main' into main
2 parents a00b9ea + a50e288 commit eb9e7e0

File tree

15 files changed

+255
-67
lines changed

15 files changed

+255
-67
lines changed

README.md

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/avaje/avaje-jsonb/blob/master/LICENSE)
55
[![Discord](https://img.shields.io/discord/1074074312421683250?color=%237289da&label=discord)](https://discord.gg/Qcqf9R27BR)
66

7-
# [Avaje-JsonB](https://avaje.io/jsonb/)
7+
# [avaje-jsonb](https://avaje.io/jsonb/)
88

99
Fast, reflection-free Json binding via apt source code generation. A light (~200kb + generated code) source code generation style alternative to Jackson's ObjectMapper or Gson. (code generation vs reflection)
1010

@@ -31,7 +31,6 @@ Built-in support for reading and writing Java’s core data types:
3131
* Enums
3232
* Other miscellaneous types (UUID, URL, URI)
3333

34-
3534
# Quick Start
3635

3736
## Step 1 - Add dependencies
@@ -41,18 +40,10 @@ Built-in support for reading and writing Java’s core data types:
4140
<artifactId>avaje-jsonb</artifactId>
4241
<version>${avaje-jsonb-version}</version>
4342
</dependency>
44-
<!-- if using spring web, add the below to use jsonb for http messaging -->
45-
<dependency>
46-
<groupId>io.avaje</groupId>
47-
<artifactId>avaje-jsonb-spring-starter</artifactId>
48-
<version>${avaje-jsonb-version}</version>
49-
</dependency>
5043
```
5144

5245
And add avaje-jsonb-generator as an annotation processor.
5346
```xml
54-
55-
<!-- Annotation processors -->
5647
<dependency>
5748
<groupId>io.avaje</groupId>
5849
<artifactId>avaje-jsonb-generator</artifactId>
@@ -102,7 +93,7 @@ JsonType<Customer> customerType = jsonb.type(Customer.class);
10293
Customer customer = ...;
10394

10495
// serialize to json
105-
String asJson = customerType.toJson(customer);
96+
String asJson = customerType.toJson(customer);
10697

10798
// deserialize from json
10899
Customer customer = customerType.fromJson(asJson);
@@ -122,14 +113,14 @@ JsonType<Customer> customerType = jsonb.type(Customer.class);
122113

123114
// only including the id and name
124115
JsonView<Customer> idAndNameView = customerType.view("(id, name)");
125-
String asJson = idAndNameView.toJson(customer);
116+
String asJson = idAndNameView.toJson(customer);
126117

127118

128119
JsonView<Customer> myView =
129120
customerType.view("(id, name, billingAddress(*), contacts(lastName, email))");
130121

131122
// serialise to json the above specified properties only
132-
String asJson = myView.toJson(customer);
123+
String asJson = myView.toJson(customer);
133124
```
134125

135126
### Generated Code
@@ -230,8 +221,8 @@ public final class AddressJsonAdapter implements JsonAdapter<Address>, ViewBuild
230221

231222
#### Changes from Moshi
232223
- Generates Java source code (rather than Kotlin)
233-
- uses custom parser inspired by dsl-json (with option of using jackson-core `JsonParser` and `JsonGenerator` as parsers)
234-
- Has no fallback to reflection - jsonb is code generation or bust.`
224+
- Uses custom parser inspired by `dsl-json` (with option of using `jackson-core`'s `JsonParser` and `JsonGenerator` as parsers)
225+
- Has no fallback to reflection - jsonb is code generation or bust.
235226
- JsonReader - Make JsonReader an interface, default implementation using `Jsonb JsonReadAdapter`
236227
- JsonWriter - Make JsonWriter an interface, default implementation using `Jsonb JsonWriteAdapter`
237228
- JsonAdapter -> Make JsonAdapter an interface.
@@ -243,11 +234,37 @@ public final class AddressJsonAdapter implements JsonAdapter<Address>, ViewBuild
243234
- Add fromObject() as a "covert from object" feature like Jackson ObjectMapper
244235
- Add naming convention support
245236
- Add `@Json.Import` to generate adapters for types that we can't put the annotation on (types we might not 'own')
237+
- Add support for generating adapters (for `@Json.Import`ed types) with annotations from Jackson, GSON and Jakarta
246238
- Add Mixin feature similar to Jackson Mixins
247239
- Add Types.listOf(), Types.setOf(), Types.mapOf() helper methods
248240
- Adds more common Java types with default built-in support - java.time types, java.util.UUID
249241
- Adds support for json views
250242

243+
## Optional extensions
244+
245+
### Optional support for Jackson, GSON and Jakarta annotations
246+
When using `@Json.Import` for types we "don't own", we provide basic support for annotations from other popular libraries.\
247+
Simply add either `jackson-annotations`, `gson` or `jakarta.json.bind-api`, and use `@Json.Import` to generate an adapter.
248+
249+
| Avaje Jsonb | Jackson | Gson | Jakarta JSON-B |
250+
|------------------|-----------------|--------------------------------|-----------------------|
251+
| `@Json.Alias` | `@JsonAlias` | `@SerializedName(alternate=…)` ||
252+
| `@Json.Creator` | `@JsonCreator` || `@JsonbCreator` |
253+
| `@Json.Ignore` | `@JsonIgnore` | `@Expose(serialize = false)` | `@JsonbTransient` |
254+
| `@Json.Property` | `@JsonProperty` | `@SerializedName` | `@JsonbProperty` |
255+
| `@Json.Raw` | `@JsonRawValue` |||
256+
| `@Json.Value` ||||
257+
258+
### Optional support for Spring Web
259+
When using Spring Web, you can use the following dependency to use avaje-jsonb for HTTP serialization:
260+
```xml
261+
<dependency>
262+
<groupId>io.avaje</groupId>
263+
<artifactId>avaje-jsonb-spring-starter</artifactId>
264+
<version>${avaje-jsonb-version}</version>
265+
</dependency>
266+
```
267+
251268
## Related works
252269
- [moshi](https://github.com/square/moshi), [reddit - why use moshi over gson](https://www.reddit.com/r/androiddev/comments/684flw/why_use_moshi_over_gson/)
253270
- [dsl-json](https://github.com/ngs-doo/dsl-json)

jsonb-generator/pom.xml

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
</licenses>
2424

2525
<dependencies>
26-
2726
<dependency>
2827
<groupId>io.avaje</groupId>
2928
<artifactId>avaje-jsonb</artifactId>
@@ -32,14 +31,6 @@
3231
<scope>provided</scope>
3332
</dependency>
3433

35-
<dependency>
36-
<groupId>com.fasterxml.jackson.core</groupId>
37-
<artifactId>jackson-annotations</artifactId>
38-
<version>2.20</version>
39-
<optional>true</optional>
40-
<scope>provided</scope>
41-
</dependency>
42-
4334
<dependency>
4435
<groupId>io.avaje</groupId>
4536
<artifactId>avaje-prisms</artifactId>
@@ -54,6 +45,29 @@
5445
<version>${spi.version}</version>
5546
</dependency>
5647

48+
<!-- optional support for other annotations -->
49+
<dependency>
50+
<groupId>com.fasterxml.jackson.core</groupId>
51+
<artifactId>jackson-annotations</artifactId>
52+
<version>2.20</version>
53+
<optional>true</optional>
54+
<scope>provided</scope>
55+
</dependency>
56+
<dependency>
57+
<groupId>com.google.code.gson</groupId>
58+
<artifactId>gson</artifactId>
59+
<version>2.13.2</version>
60+
<optional>true</optional>
61+
<scope>provided</scope>
62+
</dependency>
63+
<dependency>
64+
<groupId>jakarta.json.bind</groupId>
65+
<artifactId>jakarta.json.bind-api</artifactId>
66+
<version>3.0.1</version>
67+
<optional>true</optional>
68+
<scope>provided</scope>
69+
</dependency>
70+
5771
<!-- test dependencies -->
5872
<dependency>
5973
<groupId>io.avaje</groupId>

jsonb-generator/src/main/java/io/avaje/jsonb/generator/AliasPrism.java

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
11
package io.avaje.jsonb.generator;
22

3-
import java.util.List;
4-
import java.util.Optional;
5-
6-
import javax.lang.model.element.Element;
7-
83
import com.fasterxml.jackson.annotation.JsonAlias;
9-
4+
import com.google.gson.annotations.SerializedName;
105
import io.avaje.jsonb.Json.Alias;
116
import io.avaje.prism.GeneratePrism;
127

13-
@GeneratePrism(value = Alias.class, name = "AvajeAliasPrism", superInterfaces = AliasPrism.class)
8+
import javax.lang.model.element.Element;
9+
import java.util.List;
10+
import java.util.Optional;
11+
1412
@GeneratePrism(
15-
value = JsonAlias.class,
16-
name = "JacksonAliasPrism",
17-
superInterfaces = AliasPrism.class)
13+
value = Alias.class,
14+
name = "AvajeAliasPrism",
15+
superInterfaces = AliasPrism.class)
16+
@GeneratePrism(
17+
value = JsonAlias.class,
18+
name = "JacksonAliasPrism",
19+
superInterfaces = AliasPrism.class)
20+
@GeneratePrism(
21+
value = SerializedName.class,
22+
name = "GsonAliasPrism")
1823
public interface AliasPrism {
1924

20-
2125
static Optional<AliasPrism> getOptionalOn(Element element) {
2226
return Optional.<AliasPrism>empty()
2327
.or(() -> AvajeAliasPrism.getOptionalOn(element))
24-
.or(() -> JacksonAliasPrism.getOptionalOn(element));
28+
.or(() -> JacksonAliasPrism.getOptionalOn(element))
29+
.or(() -> GsonAliasPrism.getOptionalOn(element)
30+
.map(GsonAliasPrism::alternate)
31+
.map(aliases -> (AliasPrism) () -> aliases)
32+
.filter(prism -> !prism.value().isEmpty()));
2533
}
2634

2735
List<String> value();

jsonb-generator/src/main/java/io/avaje/jsonb/generator/CreatorPrism.java

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

77
import io.avaje.jsonb.Json.Creator;
88
import io.avaje.prism.GeneratePrism;
9+
import jakarta.json.bind.annotation.JsonbCreator;
910

1011
@GeneratePrism(
1112
value = Creator.class,
@@ -15,9 +16,15 @@
1516
value = JsonCreator.class,
1617
name = "JacksonCreatorPrism",
1718
superInterfaces = CreatorPrism.class)
19+
@GeneratePrism(
20+
value = JsonbCreator.class,
21+
name = "JakartaCreatorPrism",
22+
superInterfaces = CreatorPrism.class)
1823
public interface CreatorPrism {
1924

2025
static boolean isPresent(Element element) {
21-
return AvajeCreatorPrism.isPresent(element) || JacksonCreatorPrism.isPresent(element);
26+
return AvajeCreatorPrism.isPresent(element)
27+
|| JacksonCreatorPrism.isPresent(element)
28+
|| JakartaCreatorPrism.isPresent(element);
2229
}
2330
}

jsonb-generator/src/main/java/io/avaje/jsonb/generator/IgnorePrism.java

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,27 @@
66

77
import com.fasterxml.jackson.annotation.JsonIgnore;
88

9+
import com.google.gson.annotations.Expose;
910
import io.avaje.jsonb.Json.Ignore;
1011
import io.avaje.prism.GeneratePrism;
12+
import jakarta.json.bind.annotation.JsonbTransient;
1113

12-
@GeneratePrism(value = Ignore.class, name = "AvajeIgnorePrism", superInterfaces = IgnorePrism.class)
1314
@GeneratePrism(
14-
value = JsonIgnore.class,
15-
name = "JacksonIgnorePrism",
16-
superInterfaces = IgnorePrism.class)
15+
value = Ignore.class,
16+
name = "AvajeIgnorePrism",
17+
superInterfaces = IgnorePrism.class)
18+
@GeneratePrism(
19+
value = JsonIgnore.class,
20+
name = "JacksonIgnorePrism",
21+
superInterfaces = IgnorePrism.class)
22+
@GeneratePrism(
23+
value = Expose.class,
24+
name = "GsonIgnorePrism",
25+
superInterfaces = IgnorePrism.class)
26+
@GeneratePrism(
27+
value = JsonbTransient.class,
28+
name = "JakartaIgnorePrism",
29+
superInterfaces = IgnorePrism.class)
1730
public interface IgnorePrism {
1831

1932
static IgnorePrism getInstanceOn(Element element) {
@@ -23,7 +36,9 @@ static IgnorePrism getInstanceOn(Element element) {
2336
static Optional<IgnorePrism> getOptionalOn(Element element) {
2437
return Optional.<IgnorePrism>empty()
2538
.or(() -> AvajeIgnorePrism.getOptionalOn(element))
26-
.or(() -> JacksonIgnorePrism.getOptionalOn(element));
39+
.or(() -> JacksonIgnorePrism.getOptionalOn(element))
40+
.or(() -> GsonIgnorePrism.getOptionalOn(element))
41+
.or(() -> JakartaIgnorePrism.getOptionalOn(element));
2742
}
2843

2944
default Boolean serialize() {

jsonb-generator/src/main/java/io/avaje/jsonb/generator/JsonbProcessor.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,10 @@
44
import static io.avaje.jsonb.generator.APContext.logError;
55
import static io.avaje.jsonb.generator.APContext.logNote;
66
import static io.avaje.jsonb.generator.APContext.typeElement;
7-
import static io.avaje.jsonb.generator.Constants.JSON;
8-
import static io.avaje.jsonb.generator.Constants.JSON_IMPORT;
9-
import static io.avaje.jsonb.generator.Constants.JSON_IMPORT_LIST;
10-
import static io.avaje.jsonb.generator.Constants.JSON_MIXIN;
7+
import static io.avaje.jsonb.generator.Constants.*;
118
import static io.avaje.jsonb.generator.ProcessingContext.addImportedPrism;
129
import static io.avaje.jsonb.generator.ProcessingContext.createMetaInfWriterFor;
10+
import static io.avaje.jsonb.generator.ValuePrism.*;
1311
import static java.util.stream.Collectors.joining;
1412

1513
import java.io.IOException;
@@ -116,6 +114,7 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
116114
}
117115
APContext.setProjectModuleElement(annotations, round);
118116
readModule();
117+
119118
getElements(round, ValuePrism.PRISM_TYPE).ifPresent(this::writeValueAdapters);
120119
getElements(round, JSON).ifPresent(this::writeAdapters);
121120
getElements(round, JSON_MIXIN).ifPresent(this::writeAdaptersForMixInTypes);

jsonb-generator/src/main/java/io/avaje/jsonb/generator/ProcessingContext.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,10 @@
1010
import java.io.BufferedReader;
1111
import java.io.IOException;
1212
import java.io.InputStreamReader;
13-
import java.net.URI;
14-
import java.nio.file.Paths;
1513
import java.util.*;
1614
import javax.annotation.processing.ProcessingEnvironment;
1715
import javax.lang.model.element.Element;
1816
import javax.lang.model.element.TypeElement;
19-
import javax.lang.model.type.TypeMirror;
2017
import javax.tools.FileObject;
2118
import javax.tools.StandardLocation;
2219

jsonb-generator/src/main/java/io/avaje/jsonb/generator/PropertyPrism.java

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,43 @@
11
package io.avaje.jsonb.generator;
22

3-
import java.util.Optional;
4-
5-
import javax.lang.model.element.Element;
6-
73
import com.fasterxml.jackson.annotation.JsonProperty;
8-
4+
import com.google.gson.annotations.SerializedName;
95
import io.avaje.jsonb.Json.Property;
106
import io.avaje.prism.GeneratePrism;
7+
import jakarta.json.bind.annotation.JsonbProperty;
118

9+
import javax.lang.model.element.Element;
10+
import java.util.Optional;
11+
12+
@GeneratePrism(
13+
value = Property.class,
14+
name = "AvajePropertyPrism",
15+
superInterfaces = PropertyPrism.class)
1216
@GeneratePrism(
13-
value = Property.class,
14-
name = "AvajePropertyPrism",
15-
superInterfaces = PropertyPrism.class)
17+
value = JsonProperty.class,
18+
name = "JacksonPropertyPrism",
19+
superInterfaces = PropertyPrism.class)
1620
@GeneratePrism(
17-
value = JsonProperty.class,
18-
name = "JacksonPropertyPrism",
19-
superInterfaces = PropertyPrism.class)
21+
value = SerializedName.class,
22+
name = "GsonPropertyPrism",
23+
superInterfaces = PropertyPrism.class)
24+
@GeneratePrism(
25+
value = JsonbProperty.class,
26+
name = "JakartaPropertyPrism",
27+
superInterfaces = PropertyPrism.class)
2028
public interface PropertyPrism {
2129

2230
static boolean isPresent(Element element) {
23-
24-
return AvajePropertyPrism.isPresent(element) || JacksonPropertyPrism.isPresent(element);
31+
return AvajePropertyPrism.isPresent(element)
32+
|| (JacksonPropertyPrism.isPresent(element) && JacksonPropertyPrism.getOptionalOn(element)
33+
.map(JacksonPropertyPrism::value)
34+
.map(String::isEmpty)
35+
.isEmpty())
36+
|| GsonPropertyPrism.isPresent(element)
37+
|| (JakartaPropertyPrism.isPresent(element) && JakartaPropertyPrism.getOptionalOn(element)
38+
.map(JakartaPropertyPrism::value)
39+
.map(String::isEmpty)
40+
.isEmpty());
2541
}
2642

2743
static PropertyPrism getInstanceOn(Element element) {
@@ -31,7 +47,9 @@ static PropertyPrism getInstanceOn(Element element) {
3147
static Optional<PropertyPrism> getOptionalOn(Element element) {
3248
return Optional.<PropertyPrism>empty()
3349
.or(() -> AvajePropertyPrism.getOptionalOn(element))
34-
.or(() -> JacksonPropertyPrism.getOptionalOn(element));
50+
.or(() -> JacksonPropertyPrism.getOptionalOn(element))
51+
.or(() -> GsonPropertyPrism.getOptionalOn(element))
52+
.or(() -> JakartaPropertyPrism.getOptionalOn(element));
3553
}
3654

3755
String value();

0 commit comments

Comments
 (0)