Jackson ve Lombok'u birlikte çalıştıramaz


91

Jackson ve Lombok'u birleştirmek için deneyler yapıyorum. Bunlar benim derslerim:

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(onConstructor=@__(@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);
    }

}

Bunlar, sınıfa eklediğim JAR'lar:

Bunu Netbeans ile derliyorum (bunun gerçekten alakalı olduğunu düşünmüyorum, ancak bunu mükemmel ve aslına sadık bir şekilde yeniden üretilebilir hale getirmek için yine de bildiriyorum). Yukarıdaki beş JAR lib, proje klasörünün içinde " " adlı bir klasörde tutulur (" src", " nbproject", " test" ve " build" ile birlikte). Bunları proje özelliklerinde " JAR / Klasör Ekle " butonu ile Netbeans'e ekledim ve yukarıdaki listede olduğu gibi tam sırayla listeleniyorlar. Proje, standart "Java uygulaması" tipi bir projedir.

Ayrıca, Netbeans projesi " kaydederken derleme YAPMAYIN ", " hata ayıklama bilgisi oluşturacak ", " kullanımdan kaldırılan API'leri bildirecek ", " java bağımlılıklarını takip edecek ", " activacte açıklama işlemi " ve " editörde " activacte açıklama işlemi " yapacak şekilde yapılandırılmıştır . Netbeans'te hiçbir açıklama işlemcisi veya açıklama işleme seçeneği açıkça yapılandırılmamıştır. Ayrıca, " -Xlint:all" komut satırı seçeneği derleyici komut satırında iletilir ve derleyici harici bir VM'de çalışır.

Javac'ımın sürümü 1.8.0_72 ve java'mın sürümü 1.8.0_72-b15. Netbeans'ım 8.1.

Projem iyi derleniyor. Ancak, yürütülürken bir istisna atar. İstisna, kolayca görünen veya açıkça düzeltilebilen bir şey gibi görünmüyor. Yığın izleme dahil çıktı:

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 java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.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 java.beans.ConstructorProperties=@java.beans.ConstructorProperties(value=[x, z]), interface com.fasterxml.jackson.annotation.JsonCreator=@com.fasterxml.jackson.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

Zaten @Valueve @AllArgsConstructorek açıklamalarla rastgele bir şekilde uğraşmayı denedim , ancak daha iyi hale getiremedim.

İstisnayı google'ladım ve jackson hakkında eski bir hata raporu buldum ve açık olan başka bir tane, ancak başka bir şeyle ilişkili görünüyor . Ancak, bu hala bu hatanın ne olduğu veya nasıl düzeltileceği hakkında hiçbir şey söylemiyor. Ayrıca başka bir yere bakarak faydalı bir şey bulamadım.

Yapmaya çalıştığım şey, hem lombok hem de jackson'ın çok temel kullanımı olduğundan, bu sorunu nasıl çözeceğime dair daha fazla yararlı bilgi bulamamam garip görünüyor. Belki bir şeyi kaçırdım?

" Lombok kullanma " veya " Jackson kullanma " demekten başka , bunu nasıl çözeceğine dair bir fikri olan var mı?

Yanıtlar:


58

Eğer değişmez ama lombok ve jackson kullanarak json serileştirilebilir bir POJO istiyorsanız. Lomboks oluşturucunuzda jacksons yeni açıklamasını kullanın @JsonPOJOBuilder(withPrefix = "") Bu çözümü denedim ve çok iyi çalışıyor. Örnek kullanım

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 {

    }
}

Çok fazla sınıfınız @Buildervarsa ve standart kodun boş ek açıklamasını istemiyorsanız, açıklama engelleyicisinin boş olmasını isteyebilirsiniz.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", "");
        }
    });

Ve @JsonPOJOBuilderaçıklama ile boş oluşturucu sınıfını kaldırabilirsiniz .


Bir çözüme bağlantı memnuniyetle karşılanır, ancak lütfen cevabınızın o olmadan yararlı olduğundan emin olun: Bağlantının etrafına bağlam ekleyin, böylece kullanıcı arkadaşlarınız bunun ne olduğu ve neden orada olduğu konusunda fikir sahibi olurlar, ardından sayfanın en alakalı bölümünü alıntılayın ' hedef sayfanın mevcut olmaması durumunda yeniden bağlanma. Bir bağlantıdan biraz daha fazla olan cevaplar silinebilir.
geisterfurz007

Bu çözüm, Jackson'ın beyin ölümü tamamlanmış yapıcı tabanlı seriyi kaldırma sorunları etrafında çalışırken değişmezliği korur (çok alanlı kurucu, akıllı bir şey denemek yerine her yapıcı argümanında @JsonProperty gerektirir). (OnConstructor _ = {@ JsonCreator} 'ı şanssız denedim)
JeeBee

35

Immutable + Lombok + Jackson bir sonraki yolla elde edilebilir:

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
AllArgsConstructorZaten @Valueek açıklamanın bir parçası değil mi?
Zon

8
Açıkça eklemek @NoArgsConstructor, @Valueaçıklama tarafından oluşturulan kurucuyu geçersiz kılar , bu nedenle fazladan eklemeniz gerekir@AllArgsConstructor
Davio,

1
Bulduğum en iyi çözüm - bence - Builder modeli olmadan. Teşekkürler.
Radouxca

15

Yukarıdakilerden birkaçını denedim ve hepsi mizacıydı. Benim için gerçekten işe yarayan şey, burada bulduğum cevap .

projenizin kök dizinine bir lombok.config dosyası ekleyin (henüz yapmadıysanız)

lombok.config

ve bunu içine yapıştır

lombok.anyConstructor.addConstructorProperties=true

Ardından, pojolarınızı aşağıdaki gibi tanımlayabilirsiniz:

@Data
@AllArgsConstructor
public class MyPojo {

    @JsonProperty("Description")
    private String description;
    @JsonProperty("ErrorCode")
    private String errorCode;
}

2
Ama bu değişebilir mi?
vphilipnyc

değişmez olmak için, Getter ve Builder veya RequiredArgsConstructor ile verileri değiştirin ve tüm alanları son olarak işaretleyin
nekperu15739

8

Tam olarak aynı sorunu yaşadım, suppressConstructorProperties = trueparametreyi ekleyerek "çözdüm" (örneğinizi kullanarak):

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

Görünüşe göre Jackson java.beans.ConstructorProperties , kuruculara eklenen açıklamadan hoşlanmıyor . suppressConstructorProperties = trueParametre söyler Lombok (varsayılan olarak yapar) ekleyin değil.


7
suppressConstructorPropertiesartık kullanımdan kaldırıldı :-(
lilalinux

3
Yeni varsayılan da olduğu için bu sorun değil false.
Michael Piefel

4

@AllArgsConstructor(suppressConstructorProperties = true)kullanımdan kaldırıldı. Define lombok.anyConstructor.suppressConstructorProperties=true( https://projectlombok.org/features/configuration itibaren) ve değişim Pojo en lombok açıklama @Valueiçin @Data+ @NoArgsConstructor+ @AllArgsConstructorbenim için işler.


14
Bu, sınıfı değiştirilebilir olacak şekilde değiştirir, ki bu OP'nin istediği şey değildir
Amit Goldstein

2

Benim için lombok sürümünü şu şekilde güncellediğimde çalıştı: 'org.projectlombok: lombok: 1.18.0'


2

Jan Rieke'nin Cevabından

Lombok 1.18.4'ten bu yana, yapıcı parametrelerine hangi ek açıklamaların kopyalanacağını yapılandırabilirsiniz. Bunu şuraya ekle lombok.config:

lombok.copyableAnnotations += com.fasterxml.jackson.annotation.JsonProperty

Ardından @JsonPropertyalanlarınıza ekleyin :

...

İsim eşleşse bile her alanda bir @JsonProperty'ye ihtiyacınız olacak, ancak bu yine de takip etmek için iyi bir uygulamadır. Alıcılar yerine tercih ettiğim bunu kullanarak alanlarınızı genel final olarak da ayarlayabilirsiniz.

@ToString
@EqualsAndHashCode
@Wither
@AllArgsConstructor(onConstructor=@__(@JsonCreator))
public class TestFoo {
    @JsonProperty("xoom")
    public final String x;
    @JsonProperty("z")
    public final int z;
}

Yine de alıcılarla (+ ayarlayıcılar) çalışmalıdır.


1
Bu benim sorunumu çözdü! Çok teşekkür ederim! JSON ve POJO'lar arasında yaylı önyükleme entegrasyonu ve serileştirme konusunda takılıp kaldım ve şu hatayı alıyorum: Can not deserialize instance of java.lang.String out of START_OBJECT token... Ve bu sorunu çözdü ! Bunu olması gerekir @JsonPropertyher Yapıcı parametre ve bu ek için ek açıklama @AllArgsConstructorbu alete lombok verir.
Mark

1

Jackson'ın "mixin" modelini kullanırsanız hemen her şeyle oynamasını sağlayabilirsiniz . Temel olarak, mevcut bir sınıfa aslında o sınıfı değiştirmeden Jackson notlarını eklemenin bir yolunu sunar. Bir Lombok çözümü yerine burada önermeye eğiliyorum çünkü bu, Jackson'ın Jackson özelliği ile yaşadığı bir sorunu çözüyor, bu nedenle uzun vadeli çalışma olasılığı daha yüksek.


1

Tüm sınıflarıma şu şekilde açıklama ekledim:

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

En azından birkaç yıl boyunca tüm Lombok ve Jackson sürümleriyle çalıştı.

Misal:

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

Ve bu kadar. Lombok ve Jackson bir cazibe gibi birlikte oynuyorlar.


9
Bu değişebilir sınıftır.
ŁukaszG

0
@JsonInclude(JsonInclude.Include.NON_NULL)
@Data
public class Person {
   String id;
   String first;
   String last;
}

Veri Sınıfına ek olarak, ObjectMapper'ın doğru şekilde yapılandırılması gerekir. Bu durumda, bir ParameterNamesModule yapılandırmasıyla sorunsuz çalışıyor ve Alanların ve Oluşturucu Yöntemlerinin görünürlüğünü ayarlıyor

    om.registerModule(new ParameterNamesModule());
    om.setVisibility(FIELD, JsonAutoDetect.Visibility.ANY);
    om.setVisibility(CREATOR, JsonAutoDetect.Visibility.ANY);

O zaman beklendiği gibi çalışmalıdır.


0

Lombok'un ConstructorProperiesek açıklamayı eklememesiyle ilgili sorunlar yaşıyordum, bu yüzden diğer tarafa gittim ve Jackson'ın bu ek açıklamaya bakmasını engelledim.

Suçlu JacksonAnnotationIntrospector.findCreatorAnnotation . Farkına varmak:

if (_cfgConstructorPropertiesImpliesCreator
            && config.isEnabled(MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIES)

Ayrıca JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreator'a dikkat edin :

public JacksonAnnotationIntrospector setConstructorPropertiesImpliesCreator(boolean b)
{
    _cfgConstructorPropertiesImpliesCreator = b;
    return this;
}

Yani iki seçenek, set ya MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIESfalse veya oluşturmak JacksonAnnotationIntrospectorseti setConstructorPropertiesImpliesCreatoriçin falseve bu set AnnotationIntrospectoriçine ObjectMapperaracılığıyla ObjectMapper.setAnnotationIntrospector .

Birkaç şeye dikkat edin, Jackson 2.8.10 kullanıyorum ve bu sürümde MapperFeature.INFER_CREATOR_FROM_CONSTRUCTOR_PROPERTIESyok. Jackson'ın hangi sürümüne eklendiğinden emin değilim. Yani orada değilse, JacksonAnnotationIntrospector.setConstructorPropertiesImpliesCreatormekanizmayı kullanın .


0

Bu modüle de sahip olmalısınız. https://github.com/FasterXML/jackson-modules-java8

sonra derleyiciniz için -parameters bayrağını açın.

<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>

0

Ben de bununla bir an mücadele ettim. Ama belgelere bakarak burada ben onConstructor açıklama parametresi deneysel olarak kabul edilir ve iyi desteklenmediğini görüyoruz üzerinde benim IDE (STS 4). Jackson belgelerine göre, özel üyeler varsayılan olarak (de) serileştirilmez. Bunu çözmenin hızlı yolları var.

JsonAutoDetect ek açıklamasını ekleyin ve korumalı / özel üyeleri algılamak için uygun şekilde ayarlayın. Bu, DTO'lar için uygundur

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class SomeClass

@JsonCreator ek açıklamasına sahip bir fabrika işlevi ekleyin; bu, bazı nesne doğrulamalarına veya ek dönüştürmelere ihtiyacınız varsa en iyi sonucu verir.

public class SomeClass {

   // some code here

   @JsonCreator
   public static SomeClass factory(/* params here dressing them in @JsonProperty annotations*/) {
      return new SomeClass();
   }
}

Elbette kurucuyu kendinize de manuel olarak ekleyebilirsiniz.


-1

Benim farklı bir sorunum vardı ve bu boolean ilkel tiplerde idi.

private boolean isAggregate;

Sonuç olarak aşağıdaki hatayı veriyordu

Exception: Unrecognized field "isAggregate" (class 

Lambok dönüştürür isAggregateiçin isAggregate()bir alıcı özelliği yapma gibi içten olarak lombok için aggregateyerine isAggregate. Jackson kütüphanesi bundan hoşlanmıyor ve bunun isAggregateyerine mülke ihtiyacı var .

Bu sorunu çözmek için ilkel boolean Wrapper Boolean olarak güncellenmiştir. Türlerle ilgileniyorsanız sizin için başka seçenekler de vardır, booleanaşağıdaki referansa bakın.

Sol:

private Boolean isAggregate;

ref: https://www.baeldung.com/lombok-getter-boolean


İlkel türle isAggregate yerine aggregate kullanmayı denediniz mi? İnanıyorum ki, hatayı da çözebilir. Lütfen ayrıca bu stackoverflow.com/a/42620096/6332074'e
Muhammad Waqas Dilawar
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.