Reputation: 7400
I know this question has been asked ad nauseam; I think I have an understanding of the error, but still can't see why I am (attempting to) violate the erasure limitations. I also think I am using generics in the correct way, if not, feel free to let me know.
I have an AbstractService class (for both my Neo4j OGM and Hibernate implementations), each extended by a few classes which house a few methods that reflect the individual Entity objects. The individual entity objects all extend DomainEntity and are all both Hibernate ORM and Neo4j OGM entities.
I have two snippets of code (one working with Hibernate and the other working with Neo4j OGM). Both method calls (to the 3rd party library) have (almost) the same signature and my methods have the same signature, but my OGM-code throws the above compile-time error while my Hibernate-code does not.
OGM
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.transaction.Transaction;
public abstract class AbstractService<T extends DomainEntity> implements Service<T> {
private Session session;
@Override
public abstract Class<T> getEntityType();
public abstract String getUniqueProperty();
public abstract String getLabel();
public T getEntity(String property) {
String query = "MATCH (x:" + getLabel() + ") WHERE x." + getUniqueProperty() + " = \"" + property + "\" RETURN x";
return session.queryForObject(getEntityType(), query, Collections.EMPTY_MAP);
}
}
Here is the signature for the queryForObject method call:
public < T > T queryForObject(Class< T > objectType, String cypher, Map< String,? > parameters)
I get the following compile-time error on the return session.queryForObject(...) line:
incompatible types: DomainEntity cannot be converted to T where T is a type-variable: T extends DomainEntity declared in class AbstractService
However, if I cast the response to T
before returning it, it works and I don't understand why. The queryForObject method returns T
, which is what I am trying to return, so I don't understand why it would need to be casted to T
before returning.
EDIT I have tried adding the generic type to the method-call:
return session.<T>queryForObject(getEntityType(), query, Collections.EMPTY_MAP);
And that does not change anything.
HIBERNATE
import org.hibernate.Session;
public abstract class AbstractService<T extends DomainEntity> implements Service<T> {
private Session session;
public T getEntity(String property) {
String query = "SELECT * FROM " + getLabel() + " WHERE " + getUniqueProperty() + " = \'" + property + "\'";
return getSession().createNativeQuery(query, getEntityType()).getSingleResult();
}
@Override
public abstract Class<T> getEntityType();
public abstract String getUniqueProperty();
public abstract String getLabel();
}
Here are the signatures for the createNativeQuery and getSingleResult method calls.
public < R > NativeQuery< R > createNativeQuery(String sqlString, Class< R > resultClass)
public R getSingleResult()
The only difference between the getSingleResult() and queryForObject(...) method signatures is the queryForObject(...) method signature has the additional < T >, which I didn't think made a difference in the return type...?
Upvotes: 1
Views: 2768
Reputation: 86323
I can reproduce your error. And I can eliminate it:
return session.queryForObject(getEntityType(), query, Collections.emptyMap());
I cannot exactly tell why this solves it. But it must have something to with the fact that queryForObject()
wants a generic map (Map<String, ?>
) while Collections.EMPTY_MAP
is declared a raw (non-generic) Map
.
Upvotes: 2