ฉันจะบอกแจ็คสันให้ละเว้นคุณสมบัติที่ฉันไม่สามารถควบคุมซอร์สโค้ดได้อย่างไร


112

เรื่องสั้นขนาดยาวหนึ่งในเอนทิตีของฉันมีGeometryCollectionที่ทำให้เกิดข้อยกเว้นเมื่อคุณเรียก "getBoundary" (ทำไมถึงเป็นหนังสือเล่มอื่นตอนนี้สมมติว่านี่คือวิธีการทำงาน)

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

ขอบคุณ!

คำตอบ:


168

คุณสามารถใช้แจ็คสัน Mixins ตัวอย่างเช่น:

class YourClass {
  public int ignoreThis() { return 0; }    
}

ด้วย Mixin นี้

abstract class MixIn {
  @JsonIgnore abstract int ignoreThis(); // we don't need it!  
}

ด้วยสิ่งนี้:

objectMapper.getSerializationConfig().addMixInAnnotations(YourClass.class, MixIn.class);

แก้ไข:

ขอบคุณสำหรับความคิดเห็นใน Jackson 2.5+ API มีการเปลี่ยนแปลงและควรเรียกใช้ด้วย objectMapper.addMixIn(Class<?> target, Class<?> mixinSource)


1
และถ้าคุณสมบัติถูกสร้างขึ้นโดยเครื่องจักรและมีอักขระที่ไม่รองรับในชื่อของมัน? ชอบ '@'? JVM อนุญาต แต่คอมไพเลอร์ Java ไม่อนุญาต แจ็คสันมีวิธีแก้ปัญหานี้หรือไม่?
ทำเครื่องหมาย

3
และในแจ็คสัน 2.2 มันobjectMapper.addMixInAnnotations(Class<?> target, Class<?> mixinSource);
CorayThan

ฉันจะเพิกเฉยโดยระบุชื่อคุณสมบัติแทน getter ได้อย่างไร?
Erran Morad

68

ความเป็นไปได้อีกประการหนึ่งคือหากคุณต้องการละเว้นคุณสมบัติที่ไม่รู้จักทั้งหมดคุณสามารถกำหนดค่าตัวทำแผนที่ได้ดังนี้:

mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

5
จะเป็นการดีมากหากเราสามารถกำหนดค่า objectMapper ให้ละเว้นคุณสมบัติ specifc เท่านั้น เช่นรายงานข้อยกเว้นสำหรับฟิลด์ใหม่ / ที่ไม่รู้จักทั้งหมดยกเว้นให้พูดว่า 'myfield' คล้าย ๆmapper.configure(DeserializationFeature.failOnUnknownPropertiesExcep(new String[] {"myField"}));
ms_27

โปรดทราบว่าสิ่งนี้สามารถกำหนดค่าบนเครื่องอ่านได้โดยใช้without():mapper.reader().without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
Drew Stephens

ฉันขอแนะนำอย่างยิ่งให้ไม่ใช้กลไกนี้ ความคิดที่ "เข้มงวด" ใน Jackson ทำให้เกิดข้อผิดพลาดขึ้นในช่องที่ไม่รู้จัก / ไม่ได้จัดการเป็นจุดแข็งอย่างหนึ่งและตรงกับลักษณะการวิเคราะห์ Java ที่พิมพ์ / รวบรวมเวลาแบบคงที่ จะเป็นการดีกว่ามากหากคุณเลือกที่จะไม่จัดการชุดฟิลด์ที่ถูกละเว้นแทน
Per Lundberg


11

วิธีการตามคำอธิบายประกอบจะดีกว่า แต่บางครั้งก็จำเป็นต้องใช้งานด้วยตนเอง เพื่อจุดประสงค์นี้คุณสามารถใช้โดยไม่ต้องวิธีการObjectWriter

ObjectMapper mapper   = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
ObjectWriter writer   = mapper.writer().withoutAttribute("property1").withoutAttribute("property2");
String       jsonText = writer.writeValueAsString(sourceObject);

9
วิธีนี้ใช้ไม่ได้สำหรับฉัน แต่วิธีการมิกซ์อินทำ ฉันยังคงได้รับคุณสมบัติที่ถูกละเว้นหลังจากการทำให้เป็นอนุกรม ทำไมเราถึงมี mixins ในเมื่อเราไม่มีแอตทริบิวต์ ()
Erran Morad

9

คำอธิบายประกอบแบบมิกซ์อินทำงานได้ดีตามที่ได้กล่าวไปแล้ว ความเป็นไปได้อีกอย่างที่นอกเหนือไปจากต่อคุณสมบัติ @JsonIgnore คือการใช้ @JsonIgnoreType หากคุณมีประเภทที่ไม่ควรรวมไว้ (เช่นหากควรละเว้นอินสแตนซ์ทั้งหมดของคุณสมบัติ GeometryCollection) จากนั้นคุณสามารถเพิ่มได้โดยตรง (หากคุณควบคุมประเภท) หรือใช้มิกซ์อินเช่น:

@JsonIgnoreType abstract class MixIn { }
// and then register mix-in, either via SerializationConfig, or by using SimpleModule

สิ่งนี้จะสะดวกกว่าหากคุณมีคลาสมากมายที่มีตัวเข้าถึง 'IgnoredType getContext ()' ตัวเดียวหรือมากกว่านั้น (ซึ่งเป็นกรณีของหลาย ๆ เฟรมเวิร์ก)


5

ฉันมีปัญหาที่คล้ายกัน แต่เกี่ยวข้องกับความสัมพันธ์สองทิศทางของ Hibernate ฉันต้องการแสดงด้านหนึ่งของความสัมพันธ์และเพิกเฉยต่ออีกด้านหนึ่งโดยทางโปรแกรมขึ้นอยู่กับมุมมองที่ฉันกำลังเผชิญอยู่ ถ้าทำไม่ได้ก็จบด้วยStackOverflowExceptions ที่น่ารังเกียจ ตัวอย่างเช่นถ้าฉันมีวัตถุเหล่านี้

public class A{
  Long id;
  String name;
  List<B> children;
}

public class B{
  Long id;
  A parent;
}

ฉันต้องการที่จะละเว้นparentฟิลด์ใน B โดยทางโปรแกรมถ้าฉันมองไปที่ A และไม่สนใจchildrenฟิลด์ใน A ถ้าฉันกำลังมองไปที่ B

ฉันเริ่มจากการใช้มิกซ์อินเพื่อทำสิ่งนี้ แต่มันก็กลายเป็นเรื่องน่ากลัวอย่างรวดเร็ว คุณมีชั้นเรียนที่ไร้ประโยชน์มากมายที่มีอยู่เพื่อจัดรูปแบบข้อมูลเท่านั้น ฉันลงเอยด้วยการเขียน serializer ของตัวเองเพื่อจัดการสิ่งนี้ด้วยวิธีที่สะอาดกว่า: https://github.com/monitorjbl/json-view https://github.com/monitorjbl/json-view

ช่วยให้คุณระบุฟิลด์ที่จะละเว้นโดยทางโปรแกรม:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(JsonView.class, new JsonViewSerializer());
mapper.registerModule(module);

List<A> list = getListOfA();
String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(B.class, match()
        .exclude("parent")));

นอกจากนี้ยังช่วยให้คุณระบุมุมมองที่เรียบง่ายได้อย่างง่ายดายผ่านตัวจับคู่สัญลักษณ์ตัวแทน:

String json = mapper.writeValueAsString(JsonView.with(list)
    .onClass(A.class, match()
        .exclude("*")
         .include("id", "name")));

ในกรณีเดิมของฉันความต้องการมุมมองที่เรียบง่ายเช่นนี้คือการแสดงขั้นต่ำที่เปลือยเปล่าเกี่ยวกับพ่อแม่ / ลูก แต่ก็มีประโยชน์สำหรับการรักษาความปลอดภัยตามบทบาทของเราด้วย มุมมองที่มีสิทธิพิเศษน้อยกว่าของอ็อบเจ็กต์ที่จำเป็นในการส่งคืนข้อมูลเกี่ยวกับอ็อบเจ็กต์น้อยลง

ทั้งหมดนี้มาจาก serializer แต่ฉันใช้ Spring MVC ในแอปของฉัน เพื่อให้จัดการกับกรณีเหล่านี้ได้อย่างถูกต้องฉันได้เขียนการผสานรวมที่คุณสามารถส่งไปยังคลาส Spring controller ที่มีอยู่ได้:

@Controller
public class JsonController {
  private JsonResult json = JsonResult.instance();
  @Autowired
  private TestObjectService service;

  @RequestMapping(method = RequestMethod.GET, value = "/bean")
  @ResponseBody
  public List<TestObject> getTestObject() {
    List<TestObject> list = service.list();

    return json.use(JsonView.with(list)
        .onClass(TestObject.class, Match.match()
            .exclude("int1")
            .include("ignoredDirect")))
        .returnValue();
  }
}

ทั้งสองมีให้บริการที่ Maven Central ฉันหวังว่ามันจะช่วยคนอื่นได้นี่เป็นปัญหาที่น่าเกลียดอย่างยิ่งกับแจ็คสันที่ไม่มีทางออกที่ดีสำหรับกรณีของฉัน


นำเข้าเพื่อMatch.match()อะไร?
Pasupathi Rajamanickam

2

หากคุณต้องการยกเว้นคุณสมบัติบางอย่างสำหรับคลาสใด ๆ เสมอคุณสามารถใช้setMixInResolverวิธีการ:

    @JsonIgnoreProperties({"id", "index", "version"})
    abstract class MixIn {
    }

    mapper.setMixInResolver(new ClassIntrospector.MixInResolver(){
        @Override
        public Class<?> findMixInClassFor(Class<?> cls) {
            return MixIn.class;  
        }

        @Override
        public ClassIntrospector.MixInResolver copy() {
            return this;
        }
    });

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