Каков предпочтительный способ создания класса, который
Желательно, чтобы работало что-то вроде этого:
@Data(onConstructor = @__(@JsonCreator))
а затем все поля должны быть private final. Однако это даже не компилируется (и я не уверен, почему). С использованием
@AllArgsConstructor(onConstructor = @__(@JsonCreator))
будет компилироваться, но только дает
InvalidDefinitionException: No serializer found for class




Вы можете использовать аннотацию Lombok @Builder, чтобы сгенерировать конструктор для вашего неизменяемого класса POJO.
Но сделать созданный Lombok построитель пригодным для использования с помощью десериализации Джексона несколько сложно.
@JsonDeserialize(builder = ...)
чтобы сообщить Джексону, какой класс строителя использовать.@JsonPOJOBuilder(withPrefix = "")
чтобы сообщить Джексону, что его сеттер-методы запускают нет с with.Пример:
Неизменяемый класс POJO:
@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
}
}
Вот тест JUnit для проверки сериализации / десериализации:
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);
}
}
Другая альтернатива, которая гораздо менее подробна:
@Data
@Setter(AccessLevel.NONE)
public class Clazz {
private String field;
}
Конечно, у вас все еще может быть какой-то частный метод, который напрямую изменяет поле, но очень маловероятно, что даже будет какой-либо фактический код в @Data POJO, поэтому мы надеемся, что этого не произойдет.
Заявление об ограничении ответственности: Это будет иметь побочный эффект (возможно, полезный), заключающийся в том, что обычный Java-код не может создавать объект, поскольку существует только конструктор по умолчанию без мутаторов. Для нормального строительства вам понадобятся еще 2 аннотации:
@Data
@AllArgsConstructor
@NoArgsConstructor
@Setter(AccessLevel.NONE)
public class Clazz {
private String field;
}
добавить КонструкторСвойства:
lombok.config файл в подходящем месте со строкой:
lombok.anyConstructor.addConstructorProperties = true@Value в свой класс, чтобы сделать его неизменяемымЗатем сериализация и десериализация Джексоном работают должным образом.
Этот способ:
Обновлено: 2020-08-16
@Builder с @Value приводит к сбою этого решения. (Спасибо за комментарий от @ guilherme-blanco ниже.)
Однако, если вы также добавите, например, @AllArgsConstructor все еще работает как положено.ВНИМАНИЕ: этот подход не работает вместе с @Builder.
Ссылаясь на ответ Джозефа К. Штрауса, я пришел к следующему решению.
Простые аннотации ломбока, которые у меня сработали, выглядят так. Следующие аннотации дают вам неизменяемые классы с построителем, которые могут быть сериализованы и десериализованы Джексоном.
@Data
@Setter(AccessLevel.NONE)
@Builder(toBuilder = true)
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Clazz {
private String field;
}
Я предпочитаю это решение, потому что оно не требует дополнительных Особые аннотации Джексона и дополнительных файлы, специфичные для ломбока
Спасибо за это. Но кажется:
Ответ Томаса Фрича отлично работал с Spring Boot после добавления зависимости Jackson Dataformat в 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>
Попробуйте использовать следующий набор аннотаций для своего pojo:
@Value
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
@AllArgsConstructor
Я только что решил это следующим образом:
@Value
@Builder(setterPrefix = "with")
@JsonDeserialize(builder = Clazz.ClazzBuilder.class)
public class Clazz {
private String field;
}
В этом случае вы должны использовать методы компоновщика, такие как withField(...), что является поведением по умолчанию, используемым Джексоном.
С 15 октября 2020 года (Ломбок v1.18.16) вы просто сможете использовать аннотацию @Jacksonized.
@Jacksonized @Builder @JsonIgnoreProperties(ignoreUnknown = true) public class JacksonExample { private List<Foo> foos; }
Как описано в связанной документации, эта аннотация:
@JsonIgnoreProperties) иbuilder().withField(field) vs builder.field(field), с префиксом, настроенным в Lombok.Можем ли мы поставить этот ответ на первое место? Работает как часы :)
Я уже некоторое время использую этот подход, и он очень и очень эффективен. Одно очень небольшое улучшение состоит в том, что я всегда называю свои классы построителей _Builder. Таким образом, когда я копирую вставку для создания нового класса и т. д., Мне не нужно помнить об изменении строки в builderClassName. Раньше я называл классы Builder (без подчеркивания), но это вызывает странные конфликты с классом аннотации @Builder, когда вы делаете это с внутренними статическими классами.