指定Jacksonwriter架构

fhity93d  于 2022-11-08  发布在  其他
关注(0)|答案(2)|浏览(170)

是否可以用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();
    }
}

有没有办法为我想要的返回类型指定:
我的对象A的属性ab以及对象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"
    }
}

我不知道我的客户端可以向我的服务器发送什么样的数据,以指定我希望作为输出的数据的模式。

sd2nnvve

sd2nnvve1#

我假设您希望能够进行深度过滤(能够基于类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);
            }
        }

    }
}

下面是如何使用它完整示例
因此,例如,如果您只想返回对象A的属性"a",首先您将创建如下所示的控制器方法:

@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);
    }

如果你发送这样的请求:

输出应为{"a":1}
如果你想显示A类的属性b,使用字段s,你将发送如下请求:

并且输出应为{"b":{"s":"b test"}}
据我所知,没有其他方法可以达到你想要的(只使用Jackson)。

gt0wga4j

gt0wga4j2#

Sping Boot 动态过滤概念在这种情况下应该会有所帮助。将方法recupererrPESRetourDepuisPlateformeBLES()的返回类型修改为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为目标Response类添加注解,如下所示

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

    public B() {
    }
}

希望。这应该能解决问题。

相关问题