簡體   English   中英

指定 jackson 寫入模式

[英]Specify jackson writter schema

是否可以使用 springboot 為 Jackson 的編寫部分指定架構。

例如:

我有兩個 pojo 課程。

class A {
    int a;
    B b;

    public A() { }
    
    // Getter and Setter

}

class B {
    double d;
    String s;

    public B() { }
    
    // Getter and Setter

}

我有一個服務


public SomeClass {
    @RequestMapping(path = "/mapping", method = RequestMethod.POST)
    public A recupererPESRetourDepuisPlateformeBLES()
        return callToSomeMethodThatReturnsA();
    }
}

有沒有辦法為我想要的返回類型指定:

我的 object A的屬性ab以及 object B的屬性s

我希望客戶端以某種方式將我們想要的內容發送到服務器,並且服務器解析所需的模式並僅返回它。

我知道@JsonIgnore@JsonProperty 我也知道 GraphQL 但我想留在 Jackson。

更新 1

例子:

我已經在 Java 中實例化了這樣一個結構(這里以 JSON 表示以簡化)

"A" {
    "a": 12,
    "b": {
        "d": 23.362,
        "s": "Hello world"
    }
}

在我的請求之后,我希望服務器發送給客戶端:

"A" {
    "a": 12,
    "b": {
        "s": "Hello world"
    }
}

我不知道我的客戶端可以向我的服務器發送什么樣的數據來指定我想要的數據架構為 output。 這是問題的一部分。

Spring 引導動態過濾概念在這種情況下應該有所幫助。 修改recupererPESRetourDepuisPlateformeBLES()方法的返回類型為MappingJacksonValue。 以下是需要進行的代碼更改:

import com.fasterxml.jackson.databind.ser.FilterProvider;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;

public SomeClass {
    @RequestMapping(path = "/mapping", method = RequestMethod.POST)
    public MappingJacksonValue recupererPESRetourDepuisPlateformeBLES()
        SimpleBeanPropertyFilter propertyFilter = SimpleBeanPropertyFilter.filterOutAllExcept("s");
        FilterProvider filterProvider = new SimpleFilterProvider().addFilter("dynamicFilter", propertyFilter);


        B b = new B();
        b.setD(1d);
        b.setS("someString");

        A a = new A();
        a.setA(1);
        a.setB(b);

        MappingJacksonValue value = new MappingJacksonValue(a);
        value.setFilters(filterProvider);
        return value;
    }
}

使用@JsonFilter 注釋目標響應 class,如下所示

import com.fasterxml.jackson.annotation.JsonFilter;   
@JsonFilter("dynamicFilter")
public class B {
    double d;
    String s;

    public B() {
    }
}

希望。 這應該可以解決問題。

我假設您希望能夠進行深度過濾(能夠根據 A 類和 B 類的屬性進行過濾)。 為此,您可以使用以下過濾器:

package com.example.demo.filter;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.JsonStreamContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.Annotated;
import com.fasterxml.jackson.databind.introspect.AnnotationIntrospectorPair;
import com.fasterxml.jackson.databind.introspect.JacksonAnnotationIntrospector;
import com.fasterxml.jackson.databind.ser.PropertyFilter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;
import com.fasterxml.jackson.databind.type.TypeFactory;
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationIntrospector;

import java.util.Set;

/**
 * Sample filtering fields durring json marshalling.
 */
public class JSON {

    private static final String DEFAULT_FILTER = "__default";
    private static final String DOT = ".";

    private static final ObjectMapper MAPPER = new ObjectMapper().setAnnotationIntrospector(
            new AnnotationIntrospectorPair(
                    new FilteringAnnotationInpector(), new JaxbAnnotationIntrospector(TypeFactory.defaultInstance())
            )
    );

    public static String asString(Object object, Set<String> fields) {
        PropertyFilter filter = filter(fields);
        SimpleFilterProvider provider = new SimpleFilterProvider();
        provider.addFilter(DEFAULT_FILTER, filter);
        try {
            return MAPPER.writer(provider).writeValueAsString(object);
        } catch (JsonProcessingException ex) {
            throw new RuntimeException("failed to marshall", ex);
        }
    }

    private static PropertyFilter filter(Set<String> fields) {
        PropertyFilter filter;
        if (fields.size() > 0) {

            filter = new DeepFieldFilter(fields);
        } else {
            filter = SimpleBeanPropertyFilter.serializeAll();
        }
        return filter;
    }

    private static class FilteringAnnotationInpector extends JacksonAnnotationIntrospector {

        private static final long serialVersionUID = -8722016441050379430L;

        @Override
        public String findFilterId(Annotated a) {
            return DEFAULT_FILTER;
        }

    }

    private static class DeepFieldFilter extends SimpleBeanPropertyFilter {

        private final Set<String> includes;

        private DeepFieldFilter(Set<String> includes) {
            this.includes = includes;
        }

        private String createPath(PropertyWriter writer, JsonGenerator jgen) {
            StringBuilder path = new StringBuilder();
            path.append(writer.getName());
            JsonStreamContext sc = jgen.getOutputContext();
            if (sc != null) {
                sc = sc.getParent();
            }

            while (sc != null) {
                if (sc.getCurrentName() != null) {
                    if (path.length() > 0) {
                        path.insert(0, DOT);
                    }
                    path.insert(0, sc.getCurrentName());
                }
                sc = sc.getParent();
            }
            return path.toString();
        }

        @Override
        public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider provider, PropertyWriter writer)
                throws Exception {
            String path = createPath(writer, gen);
            if (includes.contains(path)) {
                writer.serializeAsField(pojo, gen, provider);
            } else {
                writer.serializeAsOmittedField(pojo, gen, provider);
            }
        }

    }
}

這是如何使用它的完整示例。

因此,例如,如果您只想返回 object A的屬性"a" ,首先您將創建 controller 方法,如下所示:

 @GetMapping("/test")
    public String test(@RequestBody Set<String> filterFields)  {

        B b = new B();
        b.setD(23);
        b.setS("b test");
        A a = new A();
        a.setA(1);
        a.setB(b);


        return JSON.asString(a, filterFields);
    }

如果您發送這樣的請求:

在此處輸入圖像描述

output 應該是{"a":1}

如果要顯示A class 的屬性b ,帶有字段s ,您將發送如下請求:

在此處輸入圖像描述

output 應該是{"b":{"s":"b test"}}

據我所知,沒有其他方法可以實現您想要的(僅使用傑克遜)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM