0

I have some requirements for the heterogeneous generic implementation for different types of Java objects. I can see warnings related to unchecked conversion. Any thought on the below implementation to avoid any runtime exception. Please find the below sample code.

class GenericData<T> {
  
  private final Class<T> type;
  private final static Map<Class<?>, GenericData> map = new HashMap<>(); //Warning :: GenericData is a raw type. References to generic type GenericData<T> should be parameterized

  public final static <T> GenericData<T> of(Class<T> type) {
    return map.putIfAbsent(type, new GenericData<T>(type)); // Warning :: Type safety: The expression of type GenericData needs unchecked conversion to conform to GenericData<T>
  }
  
  private GenericData(Class<T> type) {
    this.type = type;
  }
  
  public final T getDataAfterDefaultValueApplied(T Data, T Body) {
    Map<String, Object> defaultMap = getDataMap(Data);
    Map<String, Object> dataMap = getDataMap(Body);
    defaultMap.putAll(dataMap);
    final ObjectMapper mapper = new ObjectMapper();
    return mapper.convertValue(defaultMap, type);
  }

  private Map<String, Object> getDataMap(T data) {
    // Demo implementation, ignore this one
    return (Map<String, Object>) data;
  }
}
Anish
  • 133
  • 2
  • 13
  • 1
    You can't use `GenericData` alone (without a `<...>`) if you want to avoid warnings and have this type-checked. That's a raw type and [using raw types is a terrible idea](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it). Guessing at the goal of this class, I'd guess that you'll need *some* unchecked cast at some point, because you want to put objects of different types in a single map and extract them in a type-safe way. That's not really possible if the only difference between the types is a type-parameter (i.e. `GenericData` vs `GenericData`). – Joachim Sauer Apr 29 '21 at 11:16
  • I can understand the GenericData must be used with <> and yes you are right with the example (i.e. GenericData vs GenericData). And I did a small modification that rather than storing raw type GenericData, any thought on this modification : private final static Map, Object> map = new HashMap<>(); public final static GenericData of(final Class type) { return (GenericData) map.putIfAbsent(type, new GenericData(type)); } – Anish Apr 29 '21 at 11:33
  • This avoids the raw type, but still has an unchecked cast (since you're casting to `GenericData`. The runtime can only check if the object is any `GenericData>`, but it can't check if it's specifically a `GenericData`). – Joachim Sauer Apr 29 '21 at 11:44

1 Answers1

3

For containers of this kind, an unchecked operation is unavoidable. But you should try to minimize it and further, add a runtime check to ensure type safety:

class GenericData<T> {
    private final Class<T> type;
    private final static Map<Class<?>, GenericData<?>> map = new HashMap<>();

    public final static <T> GenericData<T> of(Class<T> type) {
        return map.putIfAbsent(type, new GenericData<>(type)).checkedCast(type);
    }

    private GenericData(Class<T> type) {
        this.type = type;
    }

    @SuppressWarnings("unchecked")
    private <U> GenericData<U> checkedCast(Class<U> clazz) {
        if(clazz != this.type) throw new ClassCastException(clazz + " != " + this.type);
        return (GenericData<U>)this;
    }

    // ...
}

Here, the unchecked operations are limited to the checkedCast method and it’s immediately recognizable to the reader that it has been made safe by an explicit check operation and only the compiler can’t recognize it.

Holger
  • 285,553
  • 42
  • 434
  • 765