0

My Java Generics is rusty returning to Java after a long time away.

I am trying to create a generic base class to wrap Jacksons ObjectMapper

abstract class MyBaseClass<T> {
  private Class<T> clazz;
  public void read() {
       objectMapper.readValue(json, clazz)
  }

  abstract Class<T> getGenericTypeClass();
}

The issue I am having is that sometimes T is an instance of a class, and sometimes it needs to be List<T>. My code works for the former, but I can't get it to compile when I have the list scenario. So this

class Sub extends MyBaseClass<Thing> {
    @Override
    getGenericTypeClass() {
       return Thing.class;
    }
}

works fine, but when I need List<Thing> I'm a bit lost.

hvgotcodes
  • 109,621
  • 25
  • 195
  • 231
  • 1
    If you need `List`, you might need to consider type tokens (from http://stackoverflow.com/a/75345/2413303 ) - I tinkered with them [here](http://stackoverflow.com/a/30096160/2413303) but I don't know if it's of any help. – EpicPandaForce Dec 05 '16 at 15:33
  • There is a `Thing.class` but there is not a `List.class` only a `List.class`, so the type information of `` would be lost. This external library you're using might have some other api to deal with cases like that. It really depends on the library in this case. – Jorn Vernee Dec 05 '16 at 15:33
  • But you can also look at [this article](https://bthurley.wordpress.com/2012/07/18/accessing-generic-type-info-at-runtime/) and Spring's `GenericTypeResolver` – EpicPandaForce Dec 05 '16 at 15:40
  • 2
    You need a `TypeReference` for parameterized types with Jackson. But the type has to be known at compile time, ie. not the type variable `T`. – Sotirios Delimanolis Dec 05 '16 at 15:42
  • @JornVernee I updated the question with more info. – hvgotcodes Dec 05 '16 at 15:44
  • @hvgotcodes Sotirios is right. Jackson's `TypeReference` does have the capability to store the type parameter. You could change the `Class` to `TypeReference`. You would have to pass in the concrete type in a `TypeReference` when instantiating your class. – Jorn Vernee Dec 05 '16 at 15:47

1 Answers1

1

You can't. And you shouldn't. A Thing and a List<Thing> are totally different. They are analogous to a Car and a Carpark.

I suggest always returning List<Thing>, wrapping a single Thing in a singleton List if required.

Here's one (easy) way;

public void read() {
   objectMapper.readValue("[" + json.replaceAll("^\\[|]$", "") + "]", clazz);
}

Where clazz is a TypeReference for List<Thing>.

The string manipulation guarantees the JSON will be wrapped in "[...]", adding wrapping square brackets if there are none.

Bohemian
  • 365,064
  • 84
  • 522
  • 658