Не может заставить Джексона и Ломбока работать вместе

Я экспериментирую в объединении Джексона и Ломбока. Это мои классы:

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