programing

Spring @RestController 사용자 지정 JSON 역직렬화기

topblog 2023. 7. 2. 18:56
반응형

Spring @RestController 사용자 지정 JSON 역직렬화기

일부 클래스(여기서 역할)에 사용자 지정 JSON deserializer를 사용하려고 하는데 작동할 수 없습니다.사용자 지정 역직렬화기가 호출되지 않았습니다.

Spring Boot 1.2를 사용합니다.

역직렬화기:

public class ModelDeserializer extends JsonDeserializer<Role> {

    @Override
    public Role deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        return null; // this is what should be called but it isn't
    }
}

컨트롤러:

@RestController
public class RoleController {

    @RequestMapping(value = "/role", method = RequestMethod.POST)
    public Object createRole(Role role) {
        // ... this is called
    }
}
  1. @JsonDeserialize역할에 따라

    @JsonDeserialize(using = ModelDeserializer.class)
    public class Role extends Model {
    
    }
    
  2. Jackson2ObjectMapperBuilderJava 구성에서 been

    @Bean
    public Jackson2ObjectMapperBuilder jacksonBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.deserializerByType(Role.class, new ModelDeserializer());
        return builder;
    }
    

내가 뭘 잘못하고 있는 거지?

EDIT 아마도 원인일 입니다.@RestController와 함께 작동하기 때문에@Controller...

무엇보다도 우선, 당신은 그것을 무시할 필요가 없습니다.Jackson2ObjectMapperBuilder사용자 지정 역직렬화기를 추가합니다.추가할 수 없는 경우 이 접근 방식을 사용해야 합니다.@JsonDeserialize주석사용해야 합니다.@JsonDeserialize또는 오버라이드Jackson2ObjectMapperBuilder.

놓친 것은@RequestBody주석:

@RestController
public class JacksonCustomDesRestEndpoint {

    @RequestMapping(value = "/role", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @ResponseBody
    public Object createRole(@RequestBody Role role) {
        return role;
    }
}

@JsonDeserialize(using = RoleDeserializer.class)
public class Role {
    // ......
}

public class RoleDeserializer extends JsonDeserializer<Role> {
    @Override
    public Role deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        // .................
        return something;
    }
}

기본 역직렬화기를 호출하기 전에 JSON 본문을 수정하려는 경우에 도움이 될 수 있는 매우 흥미로운 해결책도 있습니다.그리고 그것을 위해 약간의 추가적인 콩을 사용해야 한다고 상상해 봅시다. (사용).@Autowire메커니즘)

다음과 같은 컨트롤러가 있다고 가정해 보겠습니다.

@RequestMapping(value = "/order/product", method = POST)
public <T extends OrderProductInterface> RestGenericResponse orderProduct(@RequestBody @Valid T data) {
    orderService.orderProduct(data);
    return generateResponse();
}

어디에OrderProductInterface다음과 같습니다.

@JsonIgnoreProperties(ignoreUnknown = true)
@JsonSerialize(include = NON_EMPTY)
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, visible = true, property = "providerType")
@JsonSubTypes({
              @JsonSubTypes.Type(value = OrderProductForARequestData.class, name = "A")
          })
public interface OrderProductInterface{}

위의 코드는 파일 기반의 동적 역직렬화를 제공합니다.providerType구체적인 구현에 따른 검증.더 잘 이해하기 위해 다음을 고려합니다.OrderProductForARequestData다음과 같은 것이 될 수 있습니다.

public class OrderProductForARequestData implements OrderProductInterface {

    @NotBlank(message = "is mandatory field.")
    @Getter @Setter
    private String providerId;

    @NotBlank(message = "is mandatory field.")
    @Getter @Setter
    private String providerType;

    @NotBlank(message = "is mandatory field.")
    @Getter @Setter
    private String productToOrder;

}

그리고 이제 우리가 어떻게든 그것을 하고 싶어하는 것을 상상해 봅시다.providerType기본 역직렬화가 실행되기 전에 (임의 입력).그래서 객체는 의 규칙에 따라 적절하게 역직렬화됩니다.OrderProductInterface그러기 위해서는 당신은 단지 당신의 것을 수정할 수 있습니다.@Configuration클래스는 다음과 같습니다.

//here can be any annotation which will enable MVC/Boot 
@Configuration
public class YourConfiguration{

    @Autowired
    private ObjectMapper mapper;

    @Autowired
    private ProviderService providerService;

    @Override
    public void setup() {
        super.setup();
        SimpleModule module = new SimpleModule();
        module.setDeserializerModifier(new BeanDeserializerModifier() {
            @Override
            public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config, BeanDescription beanDesc, JsonDeserializer<?> deserializer) {

                if (beanDesc.getBeanClass() == OrderProductInterface.class) {
                    return new OrderProductInterfaceDeserializer(providerService, beanDesc);
                }
                return deserializer;
            }
        });

        mapper.registerModule(module);
    }

    public static class OrderProductInterfaceDeserializer extends AbstractDeserializer {

            private static final long serialVersionUID = 7923585097068641765L;

            private final ProviderService providerService;

            OrderProductInterfaceDeserializer(roviderService providerService, BeanDescription beanDescription) {
                super(beanDescription);
                this.providerService = providerService;
            }

            @Override
            public Object deserializeWithType(JsonParser p, DeserializationContext context, TypeDeserializer typeDeserializer) throws IOException {
                ObjectCodec oc = p.getCodec();
                JsonNode node = oc.readTree(p);

                //Let's image that we have some identifier for provider type and we want to detect it
                JsonNode tmp = node.get("providerId");
                Assert.notNull(tmp, "'providerId' is mandatory field");
                String providerId = tmp.textValue();
                Assert.hasText(providerId, "'providerId' can't be empty");

                // Modify node
                ((ObjectNode) node).put("providerType",providerService.getProvider(providerId));

                JsonFactory jsonFactory = new JsonFactory();
                JsonParser newParser = jsonFactory.createParser(node.toString());
                newParser.nextToken();

                return super.deserializeWithType(newParser, context, typeDeserializer);

           }

      }
}

언급URL : https://stackoverflow.com/questions/27550376/spring-restcontroller-custom-json-deserializer

반응형