2

I am working on a middleware-app which deserializes values received via RestTemplate as json-String from a legacy-API (so, no influence on "their" data model and thus needing some custom config for my objectmapper consuming this api), and the app itself serves a restful API with (partially enriched and composited) data based on the legacydata as json, too.

Now, my legacy-Mapping-Classes' Constructors are all sharing a common structure like this at the moment:

    ...
    private ObjectMapper mapper;

    public MyMapper() {
        this.mapper = new ObjectMapper();
        this.mapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
        this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }
    ...

because I use Jackson to de-serialize the json from the legacysystem. Basically I want to refactor this redundance using Springs DI Container.

So I tried to create my own Objectmapper @Component which just extends ObjectMapper like it is stated in some answers in this thread: Configuring ObjectMapper in Spring - lets call it FromLegacyObjectMapper - instead of initializing my mapper in every class, so I created one and used

@Autowired
private FromLegacyObjectMapper

(or the constructorinjection-equivalent, but for simplicitys sake..). But this had some serious sideeffects. Actually, I wasn't able to deserialize clientjson to viewmodels in my controllers anymore because of the rootvalue-wrapping, because the autowiring overwrites the spring boot standard objectmapper which I actually need when deserializing viewModels from my frontend.

I try to get it up and running like this:

frontend <---> My Api using Standard ObjectMapper <--> viewModel created by consuming legacy-Api-json using FromLegacyObjectMapper

So, what I surely could do is using a baseclass for my mappingclasses and just add the code above to the base constructor, and let every Mapperclass extend this base, but actually I hoped to find a way to use springs dependency injection container instead. I am out of ideas for now, so I hope anyone could help me out!

edit: To make it perhaps a bit clearer please see Moritz' answer below and our discussion in the comments. I am well aware I am able to use @Qualifier annotation, but this would just solve the problem if there is a way to add the @Qualifier to the standard objectmapper used in spring controllers. I'll do some research myself, but other answers are highly welcome.

Dominik
  • 2,801
  • 2
  • 33
  • 45

1 Answers1

1

I would try adding two different ObjectMappers to the Spring container. You could add something like this, for example to your Application class (assuming that is the one annotated with @SpringBootApplication):

@Bean
@Qualifier("fromLegacy")
public ObjectMapper fromLegacyObjectMapper() {

  // create and customize your "from legacy" ObjectMapper here

  return objectMapper;
}

@Bean
@Qualifier("default")
public ObjectMapper defaultObjectMapper() {

  // create your default ObjectMapper here

  return objectMapper;
}

Then you can inject the "from legacy" ObjectMapper in classes that use the legacy API like this:

public class SomeServiceUsingLegacyApi {

    private final ObjectMapper objectMapper;

    @Autowired
    public SomeServiceUsingLegacyApi(@Qualifier("fromLegacy") ObjectMapper objectMapper) {

      this.objectMapper = objectMapper;
    }

    // [...]
}

And in other classes, using the other API accordingly:

public class SomeServiceUsingOtherApi {

  private final ObjectMapper objectMapper;

  @Autowired
  public SomeServiceUsingOtherApi(@Qualifier("default") ObjectMapper objectMapper) {

    this.objectMapper = objectMapper;
  }

  // [...]
} 
anothernode
  • 5,100
  • 13
  • 43
  • 62
  • but I am not injecting the standard objectmapper to my controllers, for that is done in the spring internals. So I have no influence to add a qualifier here, do I? I've been in the .NET world for the last few years, so sorry if this sounds somewhat dumb ;) – Dominik Jun 29 '17 at 13:07
  • Nothing prevents you from adding your own beans, like `ObjectMapper` beans to your Spring Application context. And if you have different beans of the same type in your context, you can use the `@Qualifier` annotation to tell Spring when to use which bean. I'd like to give you an example to make it clearer, but I don't have enough time right now. You can also find good examples on this in "Spring in Action" by Craig Walls. – anothernode Jun 29 '17 at 14:15
  • Oh, I just now really understand your question in the comment above and that my example doesn't answer that. I would have to do more research on that myself, sorry... – anothernode Jun 29 '17 at 16:10
  • Hi Moritz, i think i'll let this question open for now and go with the baseclass-approach until perhaps someone could help me. Nonetheless, thank you! – Dominik Jun 30 '17 at 06:45