Search code examples
springjacksonautowiredobjectmapper

@autowire beans and @value properties after object mapper deserialized json


I am using spring framework.

I am using objectMapper to desiriale store.json file:

service:

objectMapper.readValue(new File(jsonFilePath), Store.class)

store.json:

{
  "type": "Store",
  "name": "myStore",
}

Store.class:

@Value("${store.size:1000}")
private Integer sroreSize;

@autowire
private storePersistency storePersistency;

public Store(@JsonProperty("name") String name) {
    super(name);
}

I am trying find out how to @autowire beans and @value properties in store.class, beans and properties that exist in applicationContext. In current example sroreSize and storePersistency still null.

I know that I can inject fields to object mapper and then use @JacksonInject annotation but I have a lot of field to inject - not a good option for me. Custom desirializer also not a good option for me.

Is there any way not to use custom desirializer or not to inject every bean/property that I need in store.class? Something that injects all the beans and properties and I simply can use it in Store.class.


Solution

  • So you want some Store fields like storePersistency and sroreSize to be initialized once at application startup (which is when Spring will setup the application context) and then at runtime create multiple different Store objects differing in some fields as name that are initialized by Jackson.

    I suggest annotating Store with @Component to get Spring to initialize @Value and @Autowired fields. The @Scope annotation will cause a new independent Store instance to be created each time. Simplified example:

    @Component
    @Scope(SCOPE_PROTOTYPE)
    class Store {
    
        private String name;
    
        @Value("${store.size:1000}")
        private Integer sroreSize;
    }
    

    Then the key is method readerForUpdating where you can pass an existing instance of Store and Jackson will update that instead of creating a new one as usually:

        Store store = context.getBean(Store.class);
        objectMapper.readerForUpdating(store).readValue("{\"name\":\"myStore\"}");
    

    Where context is a Spring ApplicationContext reference that I autowired in a test class. You don't need to use the return value of readValue in this case, just inspect the existing store variable and name will be updated.