What is the preferred way to create class that is
Preferably, I would have liked something like this to work:
@Data(onConstructor = @__(@JsonCreator))
and then have all fields to be private final
. However, this does not even compile (and I'm not sure why). Using
@AllArgsConstructor(onConstructor = @__(@JsonCreator))
will compile but only yields
InvalidDefinitionException: No serializer found for class
add ConstructorProperties :
lombok.config
file in an appropriate location with the line: lombok.anyConstructor.addConstructorProperties = true
@Value
annotation to your class to make it immutableThen serialization and deserialization by Jackson works as expected.
This method:
Edit: 2020-08-16
@Builder
with @Value
causes this solution to fail. (Thanks to comment from @guilherme-blanco below.) However, if you also add eg @AllArgsConstructor
it does still work as expected. Edit: 2021-08-19
lombok.config
file the change is not picked up unless you do a rebuild (clean then build). I have been caught out by this a few times.@Jacksonized
annotation solution is another method to achieve the desired outcome for the specific classes annotated. However, I personally prefer not to need to remember to annotate every class used for deserialization. Using lombok.config
removes this overhead.You can use Lombok's @Builder
annotation to generate a builder for your immutable POJO class. But making the Lombok-generated builder usable by Jackson's deserialization is somewhat tricky.
@JsonDeserialize(builder = ...)
to tell Jackson which is the builder class to use.@JsonPOJOBuilder(withPrefix = "")
to tell Jackson that its setter-methods do not start with with
.Example:
An immutable POJO class:
@Data
@Builder(builderClassName = "PointBuilder")
@JsonDeserialize(builder = Point.PointBuilder.class)
public class Point {
private final int x;
private final int y;
@JsonPOJOBuilder(withPrefix = "")
public static class PointBuilder {
// Lombok will add constructor, setters, build method
}
}
Here is a JUnit test to verify the serialization/deserialization:
public class PointTest extends Assert {
private ObjectMapper objectMapper = new ObjectMapper();
@Test
public void testSerialize() throws IOException {
Point point = new Point(10, 20);
String json = objectMapper.writeValueAsString(point);
assertEquals("{\"x\":10,\"y\":20}", json);
}
@Test
public void testDeserialize() throws IOException {
String json = "{\"x\":10,\"y\":20}";
Point point = objectMapper.readValue(json, Point.class);
assertEquals(new Point(10, 20), point);
}
}
As of 15 October 2020 ( Lombok v1.18.16 ), you should simply be able to use the @Jacksonized
annotation.
@Jacksonized @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class JacksonExample { private List<Foo> foos; }
As described in the linked documentation, this annotation:
@JsonIgnoreProperties
), andbuilder().withField(field)
vs builder.field(field)
to the one configured in Lombok.By referencing answer by Joseph K. Strauss I came up with following solution.
Plain lombok annotations that worked out for me looks like this. Following annotations give you immutable classes with builder that can be serialized and deserialized by Jackson.
@Data
@Setter(AccessLevel.NONE)
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Clazz {
private String field;
}
I prefer this solution because it requires no additional Jackson specific annotations and no additional lombok specific files
Another alternative that is much less verbose:
@Data
@Setter(AccessLevel.NONE)
public class Clazz {
private String field;
}
Of course, you could still have some private method that modifies the field directly, but it would be very unlikely to even have any actual code in a @Data POJO, so this would hopefully not happen.
Disclaimer: This will have the side-effect (perhaps beneficial) of not letting regular Java code create the object since there is only a default constructor with no mutators. To allow for normal construction you will need 2 more annotations:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Setter(AccessLevel.NONE)
public class Clazz {
private String field;
}
Try the following set of annotations for your pojo:
@Value
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
@AllArgsConstructor
The simplest way to configure immutable class for Jackson is to use lombok annotation: @Value
and @Jacksonized
:
@Jacksonized
@Builder
@Value
class Foo {
}
I've just solved it using this way:
@Value
@Builder(setterPrefix = "with")
@JsonDeserialize(builder = Clazz.ClazzBuilder.class)
public class Clazz {
private String field;
}
In that case, you have to use the builder methods like withField(...)
, which is the default behaviour used by jackson.
Answer by Thomas Fritsch worked perfectly with Spring Boot after adding Jackson Dataformat dependency in pom.
@Data
@Builder(builderClassName = "PointBuilder")
@JsonDeserialize(builder = Point.PointBuilder.class)
public class Point {
private final int x;
private final int y;
@JsonPOJOBuilder(withPrefix = "")
public static class PointBuilder {
// Lombok will add constructor, setters, build method
}
}
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.