Unbound generic return type in Java

ddimitrov

I am playing with some ideas about constructing Java APIs and today I spent some time thinking about this code:

public <T> T getField1(Class<?> type, Class<T> retvalType, String fieldName) {
  Object retval = ...; // boring reflection code - value could be dog, could be duck
  return retvalType.cast(retval); // cast to expected - exception is raised here
}

// usage - we manually repeat the LHS type as a parameter
int foo = getField(o, Integer.class, "foo");

This is how I would typically write the API, witht he idea that specifying the retvalType gives me extra type safety. But does it?

Because we have reflection involved, the retval type is unknown. Casting on the second line would reliably catch type mismatch only when retvalType is non-generic. On the other hand, even if we don't do this explicit cast, the Java runtime would cast the generic result when it sets it to a variable - in other words, are there any drawbacks if we rewrite the code above as:

public <T> T getField2(Class<?> type, String fieldName) {
  return ...; // boring reflection code - the value type will be checked when we assign it
}

// usage - exception is raised at the next line if types don't match
int foo = getField(o, "foo");

The advantage of the latter code is that the usage is more compact and we don't have to repeat ourselves. The disadvantage is that type cast exceptions come from non-obvious place (there is no explicit cast at the calls site), but I'm starting to think that that is OK - by specifying type literal, we only repeat what we already know, but ultimately because of reflection the program soundness is still not guaranteed.

Can anybody make a good argument why the first snippet would be preferable to the second?


Edit 1:

One argument is that by having the expected type as a parameter, we can accommodate a need to do non-trivial coercion without changing the API.

For example, the looked-up field may be of type Date, but we may be requesting long, which could be converted internally by doing date.getTime(). Still this seems far-fetched to me and there is risk of mixing responsibilities.

On the other hand, not passing the type limits the input dependencies, which makes the API more robust to changes. (Cue in 'information hiding', 'instability metric', etc).

ddimitrov

In conversation with @shmosel it came up that the runtime cast, on which the second version relies, will not necessarily happen when the LHS type is generic type.

For example, consider the code:

class Foo<T> {
  void a1(Object o) {
    // forces to be explicit about the chance of heap polution
    @SuppressWarning("unchecked")
    Set<String> a = (Set<String>) getField1(o, Set.class, "foo");
    T c = (T) getField1(o, Set.class, "foo"); // guaranteed not to compile
  }

  void a2(Object o) {
    // implicit chance of heap polution in case of Set<Date>
    Set<String> a = (Set<String>) getField2(o, "foo");
    T c = getField2(o, "foo"); // will succeed even if foo is Date
  }
}

In other words, by doing the casting in the getField() method, we get a hard guarantee that the value is of the specified class, even if it is not used, or assigned to an Object variable (which happens often in dynamic languages and reflective libraries).

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Java

Java generic return type

From Dev

Java return type generic

From Java

Java weird generic return type

From Java

Return Type of Java Generic Methods

From Java

Return type of generic method (Java)

From Dev

Java Generic Interface Return Type

From Dev

java generic method return type

From Java

Java generic function: how to return Generic type

From Java

Java 8 - Inferring generic return type with lambdas

From Java

Incompatible types in generic return type method (Java)

From Java

Java automatic return type covariance with generic subclassing

From Java

Enforcing Multiple Generic Bounds in Java Return Type

From Java

Java - Return correct type from Generic method

From Dev

Java generic methods, wildcard List return type

From Dev

Java - Return list of specified generic type

From Dev

Java type mismatch, cannot convert to return itself as the generic type

From Java

Java Generics: Generic type defined as return type only

From Java

Java Generic type inference derived from method return type

From Dev

What should be the return type of generic type implementation in java

From Dev

Generic method return generic type

From Dev

generic as a generic type in Java?

From Dev

Hibernate unbound type and no explicit target entity when using generic

From Dev

Method with generic return type

From Dev

A function with generic return type

From Java

Generic Return type for collections

From Dev

Return type in scala generic

From Dev

Springdoc with a generic return type

From Dev

Generic return type in javascript

From Dev

Narrowing a generic return type