Не может заставить Джексона и Ломбока работать вместе
Я экспериментирую в объединении Джексона и Ломбока. Это мои классы:
package testelombok;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.experimental.Wither;
@Value
@Wither
@AllArgsConstructor([email protected]__(@JsonCreator))
public class TestFoo {
@JsonProperty("xoom")
private String x;
private int z;
}
package testelombok;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xebia.jacksonlombok.JacksonLombokAnnotationIntrospector;
import java.io.IOException;
public class TestLombok {
public static void main(String[] args) throws IOException {
TestFoo tf = new TestFoo("a", 5);
System.out.println(tf.withX("b"));
ObjectMapper om = new ObjectMapper().setAnnotationIntrospector(new JacksonLombokAnnotationIntrospector());
System.out.println(om.writeValueAsString(tf));
TestFoo tf2 = om.readValue(om.writeValueAsString(tf), TestFoo.class);
System.out.println(tf2);
}
}
Это JAR, которые я добавляю в classpth:
Я компилирую его с Netbeans (я не думаю, что это действительно актуально, но я сообщаю об этом в любом случае, чтобы сделать его идеально и достоверно воспроизводимым). Пять указанных выше JAR хранятся в папке "lib
" внутри папки проекта (вместе с "src
", "nbproject
", "test
" и "build
" ). Я добавил их в Netbeans с помощью кнопки "Добавить JAR/Folder" в свойствах проекта, и они перечислены в точном порядке в списке выше. Проект является стандартным проектом типа "Java-приложение".
Кроме того, проект Netbeans настроен на "НЕ компилировать при сохранении", "генерировать информацию об отладке", "отчитывать устаревшие API", "отслеживать java-зависимости", "активировать аннотацию" и "активировать аннотацию в редакторе" ". Никакой обработчик обработки аннотации или обработки аннотации явно не настроен в Netbeans. Кроме того, параметр командной строки" -Xlint:all
" передается в командной строке компилятора, а компилятор работает на внешней виртуальной машине.
Моя версия javac - 1.8.0_72, а моя версия java - 1.8.0_72-b15. Мой Netbeans - 8.1.
Мой проект отлично компилируется. Тем не менее, он выдает исключение при его выполнении. Исключением не кажется ничего, что выглядит легко или очевидно исправляемым. Вот результат, включая stacktrace:
TestFoo(x=b, z=5)
{"z":5,"xoom":"a"}
Exception in thread "main" com.fasterxml.jackson.databind.JsonMappingException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface [email protected]es(value=[x, z]), interface [email protected]son.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
at [Source: {"z":5,"xoom":"a"}; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:296)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:269)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCacheValueDeserializer(DeserializerCache.java:244)
at com.fasterxml.jackson.databind.deser.DeserializerCache.findValueDeserializer(DeserializerCache.java:142)
at com.fasterxml.jackson.databind.DeserializationContext.findRootValueDeserializer(DeserializationContext.java:475)
at com.fasterxml.jackson.databind.ObjectMapper._findRootDeserializer(ObjectMapper.java:3890)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3785)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2833)
at testelombok.TestLombok.main(TestLombok.java:14)
Caused by: java.lang.IllegalArgumentException: Argument #0 of constructor [constructor for testelombok.TestFoo, annotations: {interface [email protected]es(value=[x, z]), interface [email protected]son.annotation.JsonCreator(mode=DEFAULT)}] has no property name annotation; must have name when multiple-parameter constructor annotated as Creator
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._addDeserializerConstructors(BasicDeserializerFactory.java:511)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory._constructDefaultValueInstantiator(BasicDeserializerFactory.java:323)
at com.fasterxml.jackson.databind.deser.BasicDeserializerFactory.findValueInstantiator(BasicDeserializerFactory.java:253)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:219)
at com.fasterxml.jackson.databind.deser.BeanDeserializerFactory.createBeanDeserializer(BeanDeserializerFactory.java:141)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer2(DeserializerCache.java:406)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createDeserializer(DeserializerCache.java:352)
at com.fasterxml.jackson.databind.deser.DeserializerCache._createAndCache2(DeserializerCache.java:264)
... 7 more
Я уже пробовал случайным образом выкрикивать аннотации @Value
и @AllArgsConstructor
, но я не мог сделать это лучше.
Я сделал исключение google'd и нашел старый отчет об ошибке на jackson и другой, который открыт, но, похоже, связан с чем-то другим. Тем не менее, это все еще ничего не говорит о том, что это за ошибка или как ее исправить. Кроме того, я не мог найти ничего полезного, смотрящего в другом месте.
Поскольку то, что я пытаюсь сделать, - это очень простое использование как ломбока, так и джексона, кажется странным, что я не мог найти более полезную информацию о том, как обходить эту проблему. Может, я что-то пропустил?
Кроме того, что просто говорю "не используйте ломбок" или "не используйте джексон", есть ли у кого-нибудь представление о том, как это решить?
Ответы
Ответ 1
Если вы хотите неизменный, но json-сериализуемый POJO, используя lombok и jackson. Используйте новую аннотацию Jacksons на вашем конструкторе @JsonPOJOBuilder(withPrefix = "")
Я попробовал это решение, и оно работает очень хорошо. Пример использования
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder;
import lombok.Builder;
import lombok.Value;
@JsonDeserialize(builder = Detail.DetailBuilder.class)
@Value
@Builder
public class Detail {
private String url;
private String userName;
private String password;
private String scope;
@JsonPOJOBuilder(withPrefix = "")
public static class DetailBuilder {
}
}
Если у вас слишком много классов с @Builder
и вы не хотите, чтобы стандартный код пустой аннотации, вы можете переопределить перехватчик аннотаций, чтобы он был пустым с помощью withPrefix
mapper.setAnnotationIntrospector(new JacksonAnnotationIntrospector() {
@Override
public JsonPOJOBuilder.Value findPOJOBuilderConfig(AnnotatedClass ac) {
if (ac.hasAnnotation(JsonPOJOBuilder.class)) {//If no annotation present use default as empty prefix
return super.findPOJOBuilderConfig(ac);
}
return new JsonPOJOBuilder.Value("build", "");
}
});
И вы можете удалить пустой класс @JsonPOJOBuilder
с @JsonPOJOBuilder
аннотации @JsonPOJOBuilder
.
Ответ 2
У меня была точно такая же проблема, я "решил" ее, добавив параметр suppressConstructorProperties = true
(на вашем примере):
@Value
@Wither
@AllArgsConstructor(suppressConstructorProperties = true)
public class TestFoo {
@JsonProperty("xoom")
private String x;
private int z;
}
Джексону явно не нравится аннотация java.beans.ConstructorProperties
добавленная в конструкторы. Параметр suppressConstructorProperties = true
указывает Lombok не добавлять его (по умолчанию).
Ответ 3
Неизменный + Ломбок + Джексон может быть достигнут следующим образом:
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
import lombok.Value;
@Value
@NoArgsConstructor(force = true, access = AccessLevel.PRIVATE)
@AllArgsConstructor
public class LocationDto {
double longitude;
double latitude;
}
class ImmutableWithLombok {
public static void main(String[] args) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
String stringJsonRepresentation = objectMapper.writeValueAsString(new LocationDto(22.11, 33.33));
System.out.println(stringJsonRepresentation);
LocationDto locationDto = objectMapper.readValue(stringJsonRepresentation, LocationDto.class);
System.out.println(locationDto);
}
}
Ответ 4
@AllArgsConstructor(suppressConstructorProperties = true)
устарел. Определите lombok.anyConstructor.suppressConstructorProperties=true
(https://projectlombok.org/features/configuration) и измените аннотацию POJO lombok от @Value
до @Data
+ @NoArgsConstructor
+ @AllArgsConstructor
работает на меня.
Ответ 5
Я попробовал несколько из вышеперечисленного, и все они были темпераментными. Что действительно сработало для меня, так это ответ, который я нашел здесь.
в корневой каталог вашего проекта добавьте файл (если вы еще этого не сделали)
lombok.config
и внутри вставьте это
lombok.anyConstructor.addConstructorProperties=true
Затем вы можете определить ваши pojos следующим образом:
@Data
@AllArgsConstructor
public class MyPojo {
@JsonProperty("Description")
private String description;
@JsonProperty("ErrorCode")
private String errorCode;
}
Ответ 6
Для меня это сработало, когда я обновил версию lombok на: 'org.projectlombok: lombok: 1.18.0'
Ответ 7
Вы можете заставить Джексона играть практически со всем, если вы используете шаблон "mixin" . В принципе, это дает вам возможность добавить аннотации Jackson к существующему классу, фактически не изменяя этот класс. Я склоняюсь к рекомендациям здесь, а не к решению Ломбока, потому что это решает проблему, с которой Джексон имеет функцию Джексона, поэтому он скорее будет работать надолго.
Ответ 8
Вам также нужен этот модуль. https://github.com/FasterXML/jackson-modules-java8
затем включите флаг -parameters для вашего компилятора.
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
Ответ 9
У меня есть все мои классы, аннотированные следующим образом:
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor
Он работал со всеми версиями Ломбока и Джексона, по крайней мере, через пару лет.
Пример:
@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor
public class Person {
String id;
String first;
String last;
}
И что это.
Ломбок и Джексон играют вместе как шарм.
Ответ 10
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class Person {
String id;
String first;
String last;
}
Дополнительно к классу данных необходимо правильно настроить ObjectMapper.
В этом случае он работает нормально с конфигурацией ParameterNamesModule и устанавливает видимость полей и методов создания.
om.registerModule(new ParameterNamesModule());
om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY);
om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);
Затем он должен работать как ожидалось.
Ответ 11
У меня были проблемы с тем, чтобы Lombok не добавлял аннотацию ConstructorProperies
поэтому пошел другим путем и запретил Джексону просматривать эту аннотацию.
Виновником является JacksonAnnotationIntrospector.findCreatorAnnotation. Обратите внимание:
if (_cfgConstructorPropertiesImpliesCreator
&& config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)
Также обратите внимание на JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator:
public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b)
{
_cfgConstructorPropertiesImpliesCreator = b;
return this;
}
Таким образом, два варианта, либо установить MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
ложь или создать JacksonAnnotationIntrospector
набор setConstructorPropertiesImpliesCreator
к false
и установить этот AnnotationIntrospector
в ObjectMapper
через ObjectMapper.setAnnotationIntrospector.
Обратите внимание на пару вещей: я использую Jackson 2.8.10, и в этой версии MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES
не существует. Я не уверен, в какой версии Джексона это было добавлено. Поэтому, если его там нет, используйте механизм JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator
.
Ответ 12
Я тоже боролся с этим на мгновение. Но просматривая здесь документацию, я вижу, что параметр аннотации onConstructor считается экспериментальным и плохо поддерживается в моей среде IDE (STS 4). Согласно документации Джексона, закрытые члены по умолчанию (de) не сериализуются. Есть быстрые способы решить эту проблему.
Добавьте аннотацию JsonAutoDetect и установите ее соответствующим образом для обнаружения защищенных/закрытых членов. Это удобно для DTO
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class SomeClass
Добавьте фабричную функцию с аннотацией @JsonCreator, это работает лучше всего, если вам нужна некоторая проверка объекта или дополнительные преобразования.
public class SomeClass {
// some code here
@JsonCreator
public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) {
return new SomeClass();
}
}
Конечно, вы также можете просто добавить конструктор в себя.
Ответ 13
От Jan Rieke Ответ
Начиная с lombok 1.18.4, вы можете настроить, в какие аннотации копировать параметры конструктора. Вставьте это в свой lombok.config
:
lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty
Затем просто добавьте @JsonProperty
в свои поля:
...
Вам понадобится @JsonProperty для каждого поля, даже если имя совпадает, но в любом случае это хорошая практика. Вы также можете установить свои поля для публичного финала, используя это, что я предпочитаю вместо получателей.
@ToString
@EqualsAndHashCode
@Wither
@AllArgsConstructor([email protected]__(@JsonCreator))
public class TestFoo {
@JsonProperty("xoom")
private final String x;
@JsonProperty("z")
private final int z;
}
Ответ 14
Попробуйте добавить @NoArgsConstructor
Ответ 15
У меня была другая проблема, и это было с булевыми примитивными типами.
private boolean isAggregate;
В результате возникла следующая ошибка
Exception: Unrecognized field "isAggregate" (class
Ламбок преобразует isAggregate
в isAggregate()
как получатель, внутренне присваивая свойству ломбоку значение aggregate
вместо isAggregate
. Библиотеке Джексона это не нравится, и вместо этого ей нужно свойство isAggregate
.
Я обновил примитивное логическое значение для Wrapper Boolean, чтобы обойти эту проблему. Есть и другие варианты, если вы имеете дело с типами boolean
, см. ссылку ниже.
Sol:
private Boolean isAggregate;
ссылка: https://www.baeldung.com/lombok-getter-boolean