I have an interface called Employee
and two implementing classes FullTimeEmployee
and PartTimeEmployee
. In a seperate class, I am attempting to use ObjectMapper
to assign the correct class. The method looks as follows
public Employee retrieveEmployee(String employeeId){
Employee employee;
var jsonString = lookupEmployee(employeeId);
employee = new ObjectMapper().readValue(jsonString, isFullTime(employeeId) ? FullTimeEmployee.class : PartTimeEmployee.class;
return employee;
}
This gives me a compiler error in the IDE where the Required Type is Class <capture of ? extends Employee>
, but provided is Class <FullTimeEmployee>
However, if I open the ternary up into a standard if...then
, everything works fine.
if (isFullTime(employeeId)){
employee = new ObjectMapper().readValue(jsonString, FullTimeEmployee.class);
} else {
employee = new ObjectMapper().readValue(jsonString, PartTimeEmployee.class);
}
What is happening here, and why does one work but not the other?
When you write your conditional expression as an argument to a method invocation, it is a poly expression.
A reference conditional expression is a poly expression if it appears in an assignment context or an invocation context (§5.2. §5.3). Otherwise, it is a standalone expression.
Passing such a conditional expression to a method invocation is an invocation context, so you have a poly expression.
What's a poly expression? This site gives a better explanation of what poly expressions are than Java tutorials or the JLS:
First, for some expressions, termed poly expressions, the deduced type can be influenced by the target type. The same expression can have different types in different contexts.
This means that the type of the conditional expression is influenced by the target type. Because Jackson's readValue
method is generic, the target type of the second parameter Class<T>
becomes Class<Employee>
based on the return type of Employee
.
But because Java's generics are invariant, a Class<FullTimeEmployee>
is not a Class<Employee>
, and a Class<PartTimeEmployee>
isn't either.
But if a conditional expression isn't a poly expression, a standalone expression, then its type can be determined without context such as target types. In this instance, it is Class<? extends Employee>
.
To remove the type mismatch due to the poly expression, you can do one of 2 things I can see, other than replacing the conditional expression into an if-then statement:
Class<? extends Employee>
. This makes it so it's not a poly expression at all.employee = new ObjectMapper().readValue(jsonString,
(Class<? extends Employee>) (isFullTime(employeeId) ? FullTimeEmployee.class : PartTimeEmployee.class));
Class<? extends Employee> c = isFullTime(employeeId) ? FullTimeEmployee.class : PartTimeEmployee.class;
Employee employee2 = om.readValue(jsonString, c);