4

I am trying to autowire a component into a custom JsonDeserializer but cannot get it right even with the following suggestions I found:

My final goal is to accept URLs to resources in different microservices and store only the ID of the resource locally. But I don't want to just extract the ID from the URL but also verify that the rest of the URL is correct.

I have tried many things and lost track a bit of what I tried but I believe I tried everything mentioned in the links above. I created tons of beans for SpringHandlerInstantiator, Jackson2ObjectMapperBuilder, MappingJackson2HttpMessageConverter, RestTemplate and others and also tried with setting the SpringHandlerInstantiator in RepositoryRestConfigurer#configureJacksonObjectMapper.

I am using Spring Boot 2.1.6.RELEASE which makes me think something might have changed since some of the linked threads are quite old.

Here's my last attempt:

@Configuration
public class JacksonConfig {

    @Bean
    public HandlerInstantiator handlerInstantiator(ApplicationContext applicationContext) {
        return new SpringHandlerInstantiator(applicationContext.getAutowireCapableBeanFactory());
    }

}
@Configuration
public class RestConfiguration implements RepositoryRestConfigurer {

    @Autowired
    private Validator validator;

    @Autowired
    private HandlerInstantiator handlerInstantiator;

    @Override
    public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
        validatingListener.addValidator("beforeCreate", validator);
        validatingListener.addValidator("beforeSave", validator);
    }

    @Override
    public void configureJacksonObjectMapper(ObjectMapper objectMapper) {
        objectMapper.setHandlerInstantiator(handlerInstantiator);
    }

}
@Component
public class RestResourceURLSerializer extends JsonDeserializer<Long> {

    @Autowired
    private MyConfig config;

    @Override
    public Long deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
        ServiceConfig serviceConfig = config.getServices().get("identity");
        URI serviceUri = serviceConfig.getExternalUrl();
        String servicePath = serviceUri.getPath();

        URL givenUrl = p.readValueAs(URL.class);
        String givenPath = givenUrl.getPath();

        if (servicePath.equals(givenPath)) {
            return Long.parseLong(givenPath.substring(givenPath.lastIndexOf('/') + 1));
        }

        return null;
    }

}

I keep getting a NullPointerException POSTing something to the API endpoint that is deserialized with the JsonDeserializer above.

user3235738
  • 335
  • 4
  • 22

1 Answers1

1

I was able to solve a similar problem by marking my deserializer constructor accept a parameter (and therefore removing the empty constructor) and marking constructor as @Autowired.

 public class MyDeserializer extends JsonDeserializer<MyEntity> {    
    private final MyBean bean;

    // no default constructor
    @Autowired
    public MyDeserializer(MyBean bean){
        this.bean = bean
    }
    ...
} 

@JsonDeserialize(using = MyDeserializer.class)
public class MyEntity{...}

My entity is marked with annotation @JsonDeserialize so I don't have to explicitly register it with ObjectMapper.

Tatiana Goretskaya
  • 536
  • 10
  • 25