it-swarm.com.ru

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

Я экспериментирую с Джексоном и Ломбоком. Это мои занятия:

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 с помощью кнопки «Add JAR/Folder» в свойствах проекта, и они перечислены в точном порядке, как в списке выше. Проект представляет собой стандартный проект типа «Java-приложение».

Кроме того, проект Netbeans настроен на «НЕ компилировать при сохранении», «генерировать отладочную информацию», «сообщить об устаревших API», «отслеживать зависимости Java», «activacte аннотация обрабатывает» и «activacte аннотация обрабатывает в редакторе». В Netbeans явно не настроен ни процессор обработки комментариев, ни опция обработки комментариев. Кроме того, параметр командной строки «-Xlint:all» передается в командной строке компилятора, и компилятор работает на внешней виртуальной машине.

Версия моего javac - 1.8.0_72, а версия Java - 1.8.0_72-b15. У меня Netbeans 8.1.

Мой проект компилируется нормально. Тем не менее, он вызывает исключение в своем исполнении. Исключением, похоже, не является то, что выглядит легко или очевидно исправимо. Вот вывод, включая трассировку стека:

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 и нашел старый отчет об ошибке на Джексоне , и еще один, который открыт, но, похоже, связан с чем-то другим . Тем не менее, это все еще ничего не говорит о том, что это за ошибка или как ее исправить. Кроме того, я не мог найти ничего полезного, глядя, что где-то еще.

Поскольку то, что я пытаюсь сделать, это очень простое использование как Ломбока, так и Джексона, кажется странным, что я не смог найти больше полезной информации о том, как обойти эту проблему. Может я что то пропустил?

Кроме того, чтобы просто сказать «не использовать lombok» или «не использовать Джексон», кто-нибудь есть какие-либо идеи о том, как решить эту проблему?

36
Victor Stafusa

Если вам нужен неизменяемый, но json-сериализуемый POJO с использованием lombok и jackson . Используйте новую аннотацию jacksons на вашем сборщике lomboks @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.

18
ganesan dharmalingam

У меня была точно такая же проблема, я «решил» ее, добавив параметр suppressConstructorProperties = true (на вашем примере):

@Value
@Wither
@AllArgsConstructor(suppressConstructorProperties = true)
public class TestFoo {
    @JsonProperty("xoom")
    private String x;
    private int z;
}

Джексону явно не нравится аннотация Java.beans.ConstructorProperties , добавленная в конструкторы. Параметр suppressConstructorProperties = true указывает Lombok не добавлять его (по умолчанию).

5
Donovan Muller

@AllArgsConstructor(suppressConstructorProperties = true) устарела. Определите lombok.anyConstructor.suppressConstructorProperties=true ( https://projectlombok.org/features/configuration ) и измените аннотацию POJO lombok с @Value на @Data + @NoArgsConstructor + @AllArgsConstructor

5
yyy

Вы также должны иметь этот модуль . 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>
1
Matt Broekhuis

Вы можете заставить Джексона играть практически со всем, если вы используете его "миксин" . По сути, это дает вам возможность добавлять аннотации Джексона в существующий класс без фактического изменения этого класса. Я склоняюсь к тому, чтобы рекомендовать его здесь, а не к решению Lombok, потому что это решает проблему, с которой Джексон сталкивается с функцией Джексона, так что с большей вероятностью он будет работать долго.

1
David Ehrmann

Для меня это сработало, когда я обновил версию lombok до: 'Org.projectlombok: lombok: 1.18.0'

1
fascynacja
@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);

Тогда все должно работать как положено.

0
Hector Delgado

Я все свои классы аннотировал так:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor

Он работал со всеми версиями Lombok и Jackson, по крайней мере, пару лет.

Пример:

@JsonAutoDetect(fieldVisibility = Visibility.ANY)
@JsonInclude(JsonInclude.Include.NON_DEFAULT)
@Data
@Accessors(fluent = true)
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    String id;
    String first;
    String last;
}

И это все .. Ломбок и Джексон играют вместе, как обаяние.

0
where_

У меня были проблемы с тем, чтобы 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 в false, либо создать JacksonAnnotationIntrospector, установить setConstructorPropertiesImpliesCreator в false и установить этот AnnotationIntrospector в ObjectMapper через ObjectMapper.setAnnotationIntrospector .

Обратите внимание на пару вещей, я использую Jackson 2.8.10, и в этой версии MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES не существует. Я не уверен, в какой версии Джексона это было добавлено. Так что, если его там нет, используйте механизм JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator.

0
John B