ฉันจะใช้ Serializer แบบกำหนดเองกับ Jackson ได้อย่างไร


111

ฉันมีคลาส Java สองคลาสที่ฉันต้องการทำให้เป็นอนุกรมกับ JSON โดยใช้ Jackson:

public class User {
    public final int id;
    public final String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

public class Item {
    public final int id;
    public final String itemNr;
    public final User createdBy;

    public Item(int id, String itemNr, User createdBy) {
        this.id = id;
        this.itemNr = itemNr;
        this.createdBy = createdBy;
    }
}

ฉันต้องการทำให้รายการเป็นอนุกรมกับ JSON นี้:

{"id":7, "itemNr":"TEST", "createdBy":3}

กับผู้ใช้ต่อเนื่องเพื่อรวมเฉพาะไฟล์id. ฉันจะสามารถกำหนดออบเจ็กต์ผู้ใช้ทั้งหมดเป็น JSON เช่น:

{"id":3, "name": "Jonas", "email": "jonas@example.com"}

ดังนั้นฉันเดาว่าฉันต้องเขียนซีเรียลไลเซอร์ที่กำหนดเองItemและลองใช้สิ่งนี้:

public class ItemSerializer extends JsonSerializer<Item> {

@Override
public void serialize(Item value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,
        JsonProcessingException {
    jgen.writeStartObject();
    jgen.writeNumberField("id", value.id);
    jgen.writeNumberField("itemNr", value.itemNr);
    jgen.writeNumberField("createdBy", value.user.id);
    jgen.writeEndObject();
}

}

ฉันทำให้อนุกรม JSON ด้วยรหัสนี้จากJackson How-to: Custom Serializers :

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule", 
                                              new Version(1,0,0,null));
simpleModule.addSerializer(new ItemSerializer());
mapper.registerModule(simpleModule);
StringWriter writer = new StringWriter();
try {
    mapper.writeValue(writer, myItem);
} catch (JsonGenerationException e) {
    e.printStackTrace();
} catch (JsonMappingException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

แต่ฉันได้รับข้อผิดพลาดนี้:

Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() (use alternative registration method?)
    at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62)
    at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54)
    at com.example.JsonTest.main(JsonTest.java:54)

ฉันจะใช้ Serializer แบบกำหนดเองกับ Jackson ได้อย่างไร


นี่คือวิธีที่ฉันจะทำกับ Gson:

public class UserAdapter implements JsonSerializer<User> {

    @Override 
    public JsonElement serialize(User src, java.lang.reflect.Type typeOfSrc,
            JsonSerializationContext context) {
        return new JsonPrimitive(src.id);
    }
}

    GsonBuilder builder = new GsonBuilder();
    builder.registerTypeAdapter(User.class, new UserAdapter());
    Gson gson = builder.create();
    String json = gson.toJson(myItem);
    System.out.println("JSON: "+json);

แต่ฉันต้องทำกับแจ็คสันตอนนี้เนื่องจาก Gson ไม่รองรับอินเทอร์เฟซ


คุณทำให้ Jackson ใช้ Serializer แบบกำหนดเองสำหรับItemอะไร / ที่ไหน ฉันมีปัญหาที่เมธอดคอนโทรลเลอร์ของฉันส่งคืนอ็อบเจ็กต์ที่ทำให้เป็นอนุกรมมาตรฐานTypeAแต่สำหรับวิธีการควบคุมเฉพาะอื่นฉันต้องการทำให้เป็นซีเรียลไลซ์ต่างกัน หน้าตาจะเป็นอย่างไร?
Don Cheadle

ฉันเขียนโพสต์เกี่ยวกับHow to Write a Custom Serializer with Jacksonซึ่งอาจเป็นประโยชน์กับบางคน
Sam Berry

คำตอบ:


51

ดังกล่าวแล้ว @JsonValue เป็นวิธีที่ดี แต่ถ้าคุณไม่สนใจซีเรียลไลเซอร์ที่กำหนดเองก็ไม่จำเป็นต้องเขียนหนึ่งสำหรับไอเท็ม แต่เป็นหนึ่งสำหรับผู้ใช้หากเป็นเช่นนั้นมันจะง่ายเพียงแค่:

public void serialize(Item value, JsonGenerator jgen,
    SerializerProvider provider) throws IOException,
    JsonProcessingException {
  jgen.writeNumber(id);
}

ความเป็นไปได้อีกประการหนึ่งคือการนำไปใช้JsonSerializableซึ่งในกรณีนี้ไม่จำเป็นต้องลงทะเบียน

เป็นข้อผิดพลาด; มันแปลก - คุณอาจต้องการอัปเกรดเป็นเวอร์ชันที่ใหม่กว่า แต่ก็ยังปลอดภัยกว่าที่จะขยายorg.codehaus.jackson.map.ser.SerializerBaseเนื่องจากจะมีการใช้งานมาตรฐานของวิธีการที่ไม่จำเป็น (เช่นทุกอย่างยกเว้นการเรียกอนุกรมจริง)


ด้วยเหตุนี้ฉันจึงได้รับข้อผิดพลาดเดียวกัน:Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.JsonTest$UserSerilizer does not define valid handledType() (use alternative registration method?) at org.codehaus.jackson.map.module.SimpleSerializers.addSerializer(SimpleSerializers.java:62) at org.codehaus.jackson.map.module.SimpleModule.addSerializer(SimpleModule.java:54) at com.example.JsonTest.<init>(JsonTest.java:27) at com.exampple.JsonTest.main(JsonTest.java:102)
Jonas

ฉันใช้ Jacskson เวอร์ชันเสถียรล่าสุด 1.8.5
Jonas

4
ขอบคุณ. ฉันจะดู ... อ๊ะ! มันง่ายจริงๆ (แม้ว่าข้อความแสดงข้อผิดพลาดจะไม่ดีก็ตาม) - คุณเพียงแค่ต้องลงทะเบียนซีเรียลไลเซอร์ด้วยวิธีการอื่นเพื่อระบุคลาสที่ซีเรียลไลเซอร์ใช้สำหรับ: ถ้าไม่ใช่ก็ต้องส่งคืนคลาสจาก handledType () ดังนั้นใช้ 'addSerializer' ที่ใช้ JavaType หรือ Class เป็นอาร์กิวเมนต์และควรใช้งานได้
StaxMan

จะเกิดอะไรขึ้นถ้าสิ่งนี้ไม่ถูกเรียกใช้?
Matej J

62

คุณสามารถใส่@JsonSerialize(using = CustomDateSerializer.class)ฟิลด์วันที่ของออบเจ็กต์ใดก็ได้ที่จะทำให้เป็นอนุกรม

public class CustomDateSerializer extends SerializerBase<Date> {

    public CustomDateSerializer() {
        super(Date.class, true);
    }

    @Override
    public void serialize(Date value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonProcessingException {
        SimpleDateFormat formatter = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZZ (z)");
        String format = formatter.format(value);
        jgen.writeString(format);
    }

}

1
มูลค่า noting: ใช้@JsonSerialize(contentUsing= ...)เมื่อใส่คำอธิบายประกอบคอลเล็กชัน (เช่น@JsonSerialize(contentUsing= CustomDateSerializer.class) List<Date> dates)
coderatchet

33

ฉันลองทำสิ่งนี้ด้วยและมีข้อผิดพลาดในโค้ดตัวอย่างบนหน้าเว็บ Jackson ที่ไม่สามารถรวม type ( .class) ในวิธี call to addSerializer()ซึ่งควรอ่านดังนี้:

simpleModule.addSerializer(Item.class, new ItemSerializer());

กล่าวอีกนัยหนึ่งนี่คือบรรทัดที่สร้างอินสแตนซ์simpleModuleและเพิ่มซีเรียลไลเซอร์ (โดยบรรทัดก่อนหน้านี้ไม่ถูกต้องแสดงความคิดเห็น):

ObjectMapper mapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule("SimpleModule", 
                                          new Version(1,0,0,null));
// simpleModule.addSerializer(new ItemSerializer());
simpleModule.addSerializer(Item.class, new ItemSerializer());
mapper.registerModule(simpleModule);

FYI: นี่คือข้อมูลอ้างอิงสำหรับโค้ดตัวอย่างที่ถูกต้อง: http://wiki.fasterxml.com/JacksonFeatureModules


9

ใช้ @JsonValue:

public class User {
    int id;
    String name;

    @JsonValue
    public int getId() {
        return id;
    }
}

@JsonValue ใช้ได้กับเมธอดเท่านั้นดังนั้นคุณต้องเพิ่มเมธอด getId คุณควรจะข้ามซีเรียลไลเซอร์ที่กำหนดเองได้ทั้งหมด


2
ฉันคิดว่าสิ่งนี้จะส่งผลต่อความพยายามทั้งหมดในการทำให้เป็นอนุกรมของผู้ใช้ทำให้ยากที่จะเปิดเผยชื่อผู้ใช้ผ่าน JSON
Paul M

ฉันไม่สามารถใช้โซลูชันนี้ได้เนื่องจากฉันต้องสามารถทำให้เป็นอนุกรมวัตถุผู้ใช้ทั้งหมดกับทุกฟิลด์ และโซลูชันนี้จะทำลายการทำให้เป็นอนุกรมนั้นเนื่องจากจะรวมเฉพาะฟิลด์ id เท่านั้น ไม่มีวิธีสร้าง serilizer ที่กำหนดเองสำหรับ Jackson เหมือนกับ Gson หรือไม่?
Jonas

1
คุณสามารถแสดงความคิดเห็นว่าทำไมมุมมอง JSON (ในคำตอบของฉัน) ไม่ตรงกับความต้องการของคุณ?
Paul M

@ ผู้ใช้: มันอาจจะเป็นทางออกที่ดีฉันกำลังอ่านและพยายาม
Jonas

2
โปรดทราบด้วยว่าคุณสามารถใช้ @JsonSerialize (โดยใช้ = MySerializer.class) เพื่อระบุการทำให้เป็นอนุกรมเฉพาะสำหรับคุณสมบัติของคุณ (ฟิลด์หรือ getter) ดังนั้นจึงใช้สำหรับคุณสมบัติของสมาชิกเท่านั้นไม่ใช่ทุกอินสแตนซ์ของประเภท
StaxMan

8

ฉันเขียนตัวอย่างสำหรับTimestamp.classSerialization / deserialization ที่กำหนดเองแต่คุณสามารถใช้กับสิ่งที่คุณต้องการได้

เมื่อสร้างตัวทำแผนที่วัตถุให้ทำดังนี้:

public class JsonUtils {

    public static ObjectMapper objectMapper = null;

    static {
        objectMapper = new ObjectMapper();
        SimpleModule s = new SimpleModule();
        s.addSerializer(Timestamp.class, new TimestampSerializerTypeHandler());
        s.addDeserializer(Timestamp.class, new TimestampDeserializerTypeHandler());
        objectMapper.registerModule(s);
    };
}

ตัวอย่างเช่นjava eeคุณสามารถเริ่มต้นได้ด้วยสิ่งนี้:

import java.time.LocalDateTime;

import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;

@Provider
public class JacksonConfig implements ContextResolver<ObjectMapper> {

    private final ObjectMapper objectMapper;

    public JacksonConfig() {
        objectMapper = new ObjectMapper();
        SimpleModule s = new SimpleModule();
        s.addSerializer(Timestamp.class, new TimestampSerializerTypeHandler());
        s.addDeserializer(Timestamp.class, new TimestampDeserializerTypeHandler());
        objectMapper.registerModule(s);
    };

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return objectMapper;
    }
}

โดยที่ serializer ควรเป็นดังนี้:

import java.io.IOException;
import java.sql.Timestamp;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class TimestampSerializerTypeHandler extends JsonSerializer<Timestamp> {

    @Override
    public void serialize(Timestamp value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
        String stringValue = value.toString();
        if(stringValue != null && !stringValue.isEmpty() && !stringValue.equals("null")) {
            jgen.writeString(stringValue);
        } else {
            jgen.writeNull();
        }
    }

    @Override
    public Class<Timestamp> handledType() {
        return Timestamp.class;
    }
}

และ deserializer บางอย่างเช่นนี้:

import java.io.IOException;
import java.sql.Timestamp;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.SerializerProvider;

public class TimestampDeserializerTypeHandler extends JsonDeserializer<Timestamp> {

    @Override
    public Timestamp deserialize(JsonParser jp, DeserializationContext ds) throws IOException, JsonProcessingException {
        SqlTimestampConverter s = new SqlTimestampConverter();
        String value = jp.getValueAsString();
        if(value != null && !value.isEmpty() && !value.equals("null"))
            return (Timestamp) s.convert(Timestamp.class, value);
        return null;
    }

    @Override
    public Class<Timestamp> handledType() {
        return Timestamp.class;
    }
}

7

นี่คือรูปแบบพฤติกรรมที่ฉันสังเกตเห็นขณะพยายามทำความเข้าใจการทำให้เป็นอนุกรมของแจ็คสัน

1) สมมติว่ามีห้องเรียนวัตถุและชั้นเรียนนักเรียน ฉันทำให้ทุกอย่างเป็นสาธารณะและเป็นขั้นสุดท้ายเพื่อความสะดวก

public class Classroom {
    public final double double1 = 1234.5678;
    public final Double Double1 = 91011.1213;
    public final Student student1 = new Student();
}

public class Student {
    public final double double2 = 1920.2122;
    public final Double Double2 = 2324.2526;
}

2) สมมติว่านี่คือ serializers ที่เราใช้ในการทำให้วัตถุเป็นอนุกรมเป็น JSON writeObjectField ใช้ serializer ของอ็อบเจ็กต์หากมีการลงทะเบียนกับ object mapper ถ้าไม่เช่นนั้นจะทำให้เป็นอนุกรมเป็น POJO writeNumberField ยอมรับเฉพาะ primitives เป็นอาร์กิวเมนต์

public class ClassroomSerializer extends StdSerializer<Classroom> {
    public ClassroomSerializer(Class<Classroom> t) {
        super(t);
    }

    @Override
    public void serialize(Classroom value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeStartObject();
        jgen.writeObjectField("double1-Object", value.double1);
        jgen.writeNumberField("double1-Number", value.double1);
        jgen.writeObjectField("Double1-Object", value.Double1);
        jgen.writeNumberField("Double1-Number", value.Double1);
        jgen.writeObjectField("student1", value.student1);
        jgen.writeEndObject();
    }
}

public class StudentSerializer extends StdSerializer<Student> {
    public StudentSerializer(Class<Student> t) {
        super(t);
    }

    @Override
    public void serialize(Student value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
        jgen.writeStartObject();
        jgen.writeObjectField("double2-Object", value.double2);
        jgen.writeNumberField("double2-Number", value.double2);
        jgen.writeObjectField("Double2-Object", value.Double2);
        jgen.writeNumberField("Double2-Number", value.Double2);
        jgen.writeEndObject();
    }
}

3) ลงทะเบียนเฉพาะ DoubleSerializer ที่มีรูปแบบเอาต์พุต DecimalFormat ###,##0.000ใน SimpleModule และผลลัพธ์คือ:

{
  "double1" : 1234.5678,
  "Double1" : {
    "value" : "91,011.121"
  },
  "student1" : {
    "double2" : 1920.2122,
    "Double2" : {
      "value" : "2,324.253"
    }
  }
}

คุณจะเห็นได้ว่าการทำให้อนุกรม POJO แตกต่างระหว่าง double และ Double โดยใช้ DoubleSerialzer for Doubles และใช้รูปแบบ String ปกติสำหรับ doubles

4) ลงทะเบียน DoubleSerializer และ ClassroomSerializer โดยไม่ต้องใช้ StudentSerializer เราคาดหวังว่าผลลัพธ์จะเป็นเช่นนั้นถ้าเราเขียน double เป็นอ็อบเจกต์มันจะทำงานเหมือน Double และถ้าเราเขียน Double เป็นตัวเลขมันจะทำงานเหมือน double ตัวแปรอินสแตนซ์นักเรียนควรเขียนเป็น POJO และทำตามรูปแบบด้านบนเนื่องจากไม่ได้ลงทะเบียน

{
  "double1-Object" : {
    "value" : "1,234.568"
  },
  "double1-Number" : 1234.5678,
  "Double1-Object" : {
    "value" : "91,011.121"
  },
  "Double1-Number" : 91011.1213,
  "student1" : {
    "double2" : 1920.2122,
    "Double2" : {
      "value" : "2,324.253"
    }
  }
}

5) ลงทะเบียน serializers ทั้งหมด ผลลัพธ์คือ:

{
  "double1-Object" : {
    "value" : "1,234.568"
  },
  "double1-Number" : 1234.5678,
  "Double1-Object" : {
    "value" : "91,011.121"
  },
  "Double1-Number" : 91011.1213,
  "student1" : {
    "double2-Object" : {
      "value" : "1,920.212"
    },
    "double2-Number" : 1920.2122,
    "Double2-Object" : {
      "value" : "2,324.253"
    },
    "Double2-Number" : 2324.2526
  }
}

ตรงตามที่คาดไว้

หมายเหตุสำคัญอีกประการหนึ่ง: หากคุณมีซีเรียลไลเซอร์หลายตัวสำหรับคลาสเดียวกันที่ลงทะเบียนด้วยโมดูลเดียวกันโมดูลจะเลือกซีเรียลไลเซอร์สำหรับคลาสนั้นที่ถูกเพิ่มล่าสุดในรายการ ไม่ควรใช้ - มันสับสนและฉันไม่แน่ใจว่ามันสอดคล้องกันแค่ไหน

Moral: หากคุณต้องการปรับแต่งการทำให้เป็นอนุกรมของไพรมารีในออบเจ็กต์ของคุณคุณต้องเขียนตัวต่ออนุกรมของคุณเองสำหรับวัตถุ คุณไม่สามารถพึ่งพาการทำให้เป็นอนุกรมของ POJO Jackson ได้


คุณลงทะเบียน ClassroomSerializer เพื่อจัดการกับเหตุการณ์ที่เกิดขึ้นเช่น Classroom ได้อย่างไร
Trismegistos

5

มุมมอง JSON ของ Jacksonอาจเป็นวิธีที่ง่ายกว่าในการบรรลุความต้องการของคุณโดยเฉพาะอย่างยิ่งหากคุณมีความยืดหยุ่นในรูปแบบ JSON ของคุณ

หาก{"id":7, "itemNr":"TEST", "createdBy":{id:3}}เป็นการแสดงที่ยอมรับได้สิ่งนี้จะทำได้ง่ายมากโดยใช้รหัสน้อยมาก

คุณเพียงแค่ใส่คำอธิบายประกอบฟิลด์ชื่อของผู้ใช้ว่าเป็นส่วนหนึ่งของข้อมูลพร็อพเพอร์ตี้และระบุมุมมองอื่นในคำขอการทำให้เป็นอนุกรมของคุณ (ฟิลด์ที่ไม่ได้ใส่คำอธิบายประกอบจะรวมไว้โดยค่าเริ่มต้น)

ตัวอย่างเช่น: กำหนดมุมมอง:

public class Views {
    public static class BasicView{}
    public static class CompleteUserView{}
}

อธิบายผู้ใช้:

public class User {
    public final int id;

    @JsonView(Views.CompleteUserView.class)
    public final String name;

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

และต่อเนื่องขอมุมมองที่ไม่มีฟิลด์ที่คุณต้องการซ่อน (ฟิลด์ที่ไม่มีคำอธิบายประกอบจะถูกทำให้เป็นอนุกรมตามค่าเริ่มต้น):

objectMapper.getSerializationConfig().withView(Views.BasicView.class);

ฉันพบว่า Jackson JSON Views ใช้ยากและไม่สามารถหาทางออกที่ดีสำหรับปัญหานี้ได้
Jonas

Jonas - ฉันได้เพิ่มตัวอย่างแล้ว ฉันพบว่ามุมมองเป็นทางออกที่ดีมากสำหรับการจัดลำดับวัตถุเดียวกันในรูปแบบต่างๆ
Paul M

ขอบคุณสำหรับตัวอย่างที่ดี นี่เป็นทางออกที่ดีที่สุด แต่ไม่มีทางที่จะได้รับcreatedByเป็นมูลค่าแทนที่จะเป็นวัตถุ?
Jonas

setSerializationView()ดูเหมือนจะเลิกใช้งานแล้วดังนั้นฉันจึงใช้mapper.viewWriter(JacksonViews.ItemView.class).writeValue(writer, myItem);แทน
Jonas

สงสัยใช้ jsonviews วิธีแก้ปัญหาที่รวดเร็วและสกปรกที่ฉันใช้ก่อนที่จะค้นพบมุมมองคือเพียงแค่คัดลอกคุณสมบัติที่ฉันสนใจลงในแผนที่แล้วจัดลำดับแผนที่
Paul M

5

ในกรณีของฉัน (Spring 3.2.4 และ Jackson 2.3.1) การกำหนดค่า XML สำหรับ serializer แบบกำหนดเอง:

<mvc:annotation-driven>
    <mvc:message-converters register-defaults="false">
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper">
                <bean class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean">
                    <property name="serializers">
                        <array>
                            <bean class="com.example.business.serializer.json.CustomObjectSerializer"/>
                        </array>
                    </property>
                </bean>
            </property>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>

อยู่ในวิธีที่อธิบายไม่ได้ถูกเขียนทับกลับไปเป็นค่าเริ่มต้นโดยบางสิ่ง

สิ่งนี้ใช้ได้ผลสำหรับฉัน:

CustomObject.java

@JsonSerialize(using = CustomObjectSerializer.class)
public class CustomObject {

    private Long value;

    public Long getValue() {
        return value;
    }

    public void setValue(Long value) {
        this.value = value;
    }
}

CustomObjectSerializer.java

public class CustomObjectSerializer extends JsonSerializer<CustomObject> {

    @Override
    public void serialize(CustomObject value, JsonGenerator jgen,
        SerializerProvider provider) throws IOException,JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeNumberField("y", value.getValue());
        jgen.writeEndObject();
    }

    @Override
    public Class<CustomObject> handledType() {
        return CustomObject.class;
    }
}

ไม่<mvc:message-converters>(...)</mvc:message-converters>จำเป็นต้องมีการกำหนดค่า XML ( ) ในโซลูชันของฉัน


1

หากข้อกำหนดเดียวของคุณในซีเรียลไลเซอร์ที่กำหนดเองของคุณคือการข้ามการทำให้เป็นอนุกรมของnameฟิลด์Userให้ทำเครื่องหมายเป็นชั่วคราว แจ็คสันจะไม่ทำให้เป็นอนุกรมหรือยกเลิกการกำหนดค่าฟิลด์ชั่วคราว

[ดูเพิ่มเติม: เหตุใด Java จึงมีฟิลด์ชั่วคราว ]


ฉันจะทำเครื่องหมายไว้ที่ไหน ในUser-class? แต่ฉันจะทำให้เป็นซีเรียลไลซ์วัตถุผู้ใช้ทั้งหมดด้วย เช่นเป็นอันดับแรกเท่านั้นทั้งหมดitems(มีเพียงuserIdเป็นข้อมูลอ้างอิงเพื่อวัตถุผู้ใช้) usersแล้วอันดับทั้งหมด ในกรณีนี้ฉันไม่สามารถทำเครื่องหมาย fiels ในUser-class
Jonas

เนื่องจากข้อมูลใหม่นี้วิธีนี้จะไม่ได้ผลสำหรับคุณ ดูเหมือนว่าแจ็คสันกำลังมองหาข้อมูลเพิ่มเติมสำหรับวิธีการซีเรียลไลเซอร์แบบกำหนดเอง (handledType () ต้องการการแทนที่หรือไม่)
Mike G

ใช่ แต่ไม่มีความเข้าใจเกี่ยวกับhandledType()เมธอดในเอกสารที่ฉันเชื่อมโยงและเมื่อ Eclipse สร้างเมธอดในการใช้งานไม่handledType()ถูกสร้างขึ้นฉันจึงสับสน
Jonas

ฉันไม่แน่ใจเพราะวิกิที่คุณเชื่อมโยงไม่ได้อ้างอิง แต่ในเวอร์ชัน 1.5.1 มี handledType () และดูเหมือนว่าข้อยกเว้นจะบ่นว่าเมธอดหายไปหรือไม่ถูกต้อง (คลาสฐานส่งคืนค่าว่างจากเมธอด) jackson.codehaus.org/1.5.1/javadoc/org/codehaus/jackson/map/…
Mike G


0

ปัญหาในกรณีของคุณคือ ItemSerializer ไม่มีเมธอด handledType () ซึ่งต้องถูกแทนที่จาก JsonSerializer

    public class ItemSerializer extends JsonSerializer<Item> {

    @Override
    public void serialize(Item value, JsonGenerator jgen,
            SerializerProvider provider) throws IOException,
            JsonProcessingException {
        jgen.writeStartObject();
        jgen.writeNumberField("id", value.id);
        jgen.writeNumberField("itemNr", value.itemNr);
        jgen.writeNumberField("createdBy", value.user.id);
        jgen.writeEndObject();
    }

   @Override
   public Class<Item> handledType()
   {
    return Item.class;
   }
}

ดังนั้นคุณได้รับข้อผิดพลาดที่ชัดเจนซึ่งไม่ได้กำหนดhandledType ()

Exception in thread "main" java.lang.IllegalArgumentException: JsonSerializer of type com.example.ItemSerializer does not define valid handledType() 

หวังว่ามันจะช่วยใครบางคน ขอบคุณที่อ่านคำตอบของฉัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.