Is it possible with generics? - java

I have class:
public class GenericDAO<T, ID extends Serializable> {
private final EntityManager em;
private final Class<T> entityClass;
public GenericDAO(EntityManager em) {
this.em = em;
ParameterizedType genericSuperClass = (ParameterizedType) getClass().getGenericSuperclass();
this.entityClass = (Class<T>) genericSuperClass.getActualTypeArguments()[0];
}
}
If I extend this class all works fine. Now I want to use this class directly (see code belove, CRUDBean is implementation of CRUDService) - it is necessary to rewrite constructor to get particular class.
#Remote(CRUDService.class)
#Stateless
public class CRUDBean<T extends EntityBase> implements CRUDService<T> {
#PersistenceContext
private EntityManager entityManager;
#Override
public long size(String whereClause, Map<String, Object> whereParameters) {
return new GenericDAO<T, Long>(entityManager).size(whereClause, whereParameters);
}
}
How to write such generics service?

Yes, you would need to create a separate constructor.
Your current constructor assumes that this is an instance of a subclass of GenericDAO, and it uses that fact to get the type parameter for you through getClass().getGenericSuperclass().getActualTypeArguments().
To use GenericDAO directly, you should create a GenericDAO constructor which takes the entity class (whatever type T really is) as an argument. Then provide the entity class in CRUDBean.size() or wherever you need to instantiate your GenericDAO.
If you don't have the actual class available in CRUDBean, have three choices:
Create a CRUDBean constructor which takes the entity class as an argument.
Add a parameter to size() which takes the entity class as an argument.
Use the same trick as in the current GenericDAO constructor to get it, but with getGenericInterfaces() instead.

I would suggest using an explicit "type token", rather than reusing a class.

The usual, and easiest, way around this to pass an instance of the class to the constructor:
public GenericDAO(EntityManager em, Class<T> entityClass) {
this.em = em;
this.entityClass = entityClass;
}
Then call it like this:
public long size(String whereClause, Map<String, Object> whereParameters, Class<T> entityClass) {
return new GenericDAO<T, Long>(entityManager, entityClass).size(whereClause, whereParameters);
}

Related

Using generics and jpa EntityManager methods

Can I use generics and JPA together?
I am trying to persist objects of four classes to my db. Here's my PersistService class:
public class PersistService<T> {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("fileUploadProject");
public static EntityManager getEntityManager() {
return emf.createEntityManager();
}
// Write Client to Database
public static <T> void persist(T obj) {
EntityManager em = getEntityManager();
EntityTransaction et = em.getTransaction();
et.begin();
em.persist(obj);
et.commit();
em.close();
}
}
But then I get into a problem with removing the object. I have the following method in the PersistService class in addition to the above:
// Remove an object from the Database if they exist
public static <T> void remove(Long id) {
EntityManager em = getEntityManager();
EntityTransaction et = em.getTransaction();
<T> obj = em.find(<T>.class, id);
}
The final line is giving me a compile time error. I've tried <T>.class T Class<T> and T.class as well, but it still gives me a compile time error. Just learning about Type Erasure, is this error because of that? How do I resolve this issue?
You have started using a good pattern. The next step is to create a subclass of PersistService for each of your entity types. I will also mention that in the long run you probably want to have a common base class or interface for each of your entities. For example, I will call it Entity. This base class (if it is a class rather than interface) can be abstract and can define common methods for all of your entities.
public interface Entity {
long getId();
}
You can use the methods defined by Entity in your implementation of PersistService (which you may find handy as you add more generic entity-related business logic in this base service or elsewhere in your code).
Your entity A looks like
public class A extends Entity {
}
Your PersistService becomes
public abstract class PersistService<T extends Entity> {
// Your common methods (persist, remove, etc.).
public abstract Class<T> getEntityClass();
}
Your entity-specific services look like this
public class APersistService extends PersistService<A> {
public Class<A> getEntityClass() {
return A.class;
}
}
You then use the getEntityClass() method when you implement PersistService.remove().
While the entity-specific subclasses solve the problem of getting the specific class object in the face of type erasure, you will find that you end up wanting the subclass to support entity-specific queries as well.
I may have the answer you are searching for, well, to have generic type during compile time isn't something that easy. Since java don't allow you to do that directly.
I have a hack myself, can you try something like this ?
Be sure to handle your exceptions.
static <T> Class getGenericType(T t){
return getType(t);
}
static Class<?> getType(Object o){
return o.getClass();
}

injecting generics with roboguice

I'm trying to inject instances with generics and i'm getting the following error:
HasOne<ModelClass> cannot be used as a key; It is not fully specified.
I've read elsewhere that safest way to do this is to explicitly name the class to be used in the generic when using the injector to get an instance but i'd like to be a little cleaner. I'm trying to create Relationship objects between Models.
Here is my simplified Model class
public class Model {
#Inject
Injector injector;
public <ModelClass extends Model> HasOne<ModelClass> hasOne(Class<ModelClass> clazz) {
HasOne<ModelClass> hasOne = injector.getInstance(Key.get(new TypeLiteral<HasOne<ModelClass>>() {
}));
hasOne.init(clazz);
return hasOne;
}
}
My HasOne relationship
public class HasOne<T extends Model> {
Class clazz;
public void init(Class<T> clazz){
this.clazz = clazz;
}
#Inject
Injector injector;
public T get(){
return (T) injector.getInstance(clazz);
}
}
Test Model #1
public class TestModel extends Model {
public HasOne<ExampleModel> exampleModel(){
return hasOne(ExampleModel.class);
}
}
Test Model #2
public class ExampleModel extends Model {
}
I get the error when doing this
TestModel testModel = RoboGuice.getInjector(context).getInstance(TestModel.class);
HasOne<ExampleModel> relationship = testModel.exampleModel();
I'm trying to hide away the ugly relationship creation and keep it in the Model class
You cannot use new TypeLiteral<T>() { } if T is a type parameter, it has to be a fully-specified type. Luckily, since you have an instance of Class<ModelClass>, you can do this:
(Key<HasOne<ModelClass>>) Key.get(TypeLiteral.get(Types.newParameterizedType(HasOne.class, clazz)))
You'll get a warning on the cast but it is safe to suppress it.

Class Cast Exception Generics Reflection ParameterizedType

I have looked for an answer on Stack for a while. All the answers look like they say I already have the right answer, but I still keep getting a class cast exception for the first line in the constructor below.
SEVERE: Exception while loading the app : EJB Container initialization error
java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType
at com.domain.security.logging.ElsAbstractCrudClass.<init>(ElsAbstractCrudClass.java:54)
Here's the code. After looking at the documentation I still can't figure it out. I'm relatively new to generics and reflection so need some help. TIA.
public abstract class ElsAbstractCrudClass<T> {
Class<T> entity;
public ElsAbstractCrudClass() {
[line 54] ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass();
Type type = genericSuperclass.getActualTypeArguments()[0];
this.entity = (Class<T>) type;
}
}
Here is a subclass of the abstract crud class (SessionLog is a JPA entity):
#Stateless
public class SessionLogger extends ElsAbstractCrudClass<SessionLog> {
#PersistenceContext(unitName = "ELS_Soulard_PU")
private EntityManager em;
#EJB
DozerInstantiator di;
//SessionLog entity;
//SessionLog sessionLog = new SessionLog();
static final Logger logger = Logger.getLogger(SessionLogger.class.getSimpleName());
public SessionLogger() {
}
...
getGenericSuperclass returns an instance of ParameterizedType if the super class is generic, and an instance of Class if it is not. Presumably you have something like:
class A extends B { ... }
class B extends ElsAbstractCrudClass<Person> { ... }
Now, getClass() return A.class with superclass B.class, which is not generic ...
You could generalize your code snippet to work as long as the runtime class is not generic (recursively walking the type hierarchy, replacing type parameters by their definitions as you go). However, unless you have dozens of crud classes, requiring the subclass to pass the proper class object is easier:
public abstract class ElsAbstractCrudClass<T> {
final Class<T> entityClass;
public ElsAbstractCrudClass(Class<T> entityClass) {
this.entityClass = entityClass;
}
}
You got this error because EJB Container extend your Stateless bean to wrap EJB specific logic on method invocation. So at deployment time you have somthing like this:
ContainerSubclass extends SessionLogger {}
Solutions:
1) In your constructor first call
... = getClass().getSuperClass();
...
2) or code against interfaces so EJB container would create Dynamic Proxy through reflection.
Another way to run into trouble is if your extending class uses the raw type, not the generic type. In other words, this subclass will generate your exception, because its supertype is simply the raw type ElsAbstractCrudClass.
public class EE extends ElsAbstractCrudClass { ... }
But this one will not because its supertype is the generic type ElsAbstractCrudClass
public class EE extends ElsAbstractCrudClass<String> { ... }

how to call generic method with no parameters?

I need to write java generic method that gets no parameter and returns a List.
This generic method is used hibernate:
public <T> List list() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
List result = session.createQuery("from " + T.class.getName()).list();
return result;
}
I am tring to invoke this method. I tried the following but it creates compilation errors:
mgr.list<User>();
mgr.list()<User>;
mgr.list(<User>);
How can I call this method?
You forgot this one:
mgr.<User>list()
I believe what you're trying to accomplish requires some refactoring. It looks like you're trying to create a generic Dao class that you can reuse to query any Model object. The problem is that without passing the class to the method, you can't get the type of the <T> generic at runtime.
One way to accomplish what you want is to create a base dao, which is extended by specific implementations that know the class they're dealing with at compile time.
public abstract class AbstractDao<T>{
private Class<T> clazz;
public AbstractDao(Class<T> clazz){
this.clazz = clazz;
}
public List<T> list() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
List result = session.createQuery("from " + clazz.getName()).list();
return (List<T>) result;
}
}
Then extend the class:
class UserDao extends AbstractDao<User>{
public UserDao(){
super(User.class);
}
}
Then call the method:
List<User> users = userDao.list();
It may have something to do with "type erasure", because of using generics. When you call
T.class.getName()
that T type is erased before run time. It is not available at runtime, it is only used at compile time to make sure type safety. You probably need to write some code to get thy type of the persitence class at runtime, and then use that in mgr class. An exmaple is
public abstract class GenericHibernateDAO<T, ID extends Serializable>
implements GenericDAO<T, ID> {
private Class<T> persistentClass;
private Session session;
public GenericHibernateDAO() {
this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
// more methods
}
from https://community.jboss.org/wiki/GenericDataAccessObjects?_sscc=t
Here, it has persistentClass which is set to parameter type at construction time, then that persistentClass is in the class, whenever needed.

Using guice to pass in a run-time parameter to constructor

If I have the following class:
public class ObjectDAOMongoDBImpl<T> extends GenericDAOMongoDBImpl<T, ObjectId> implements ObjectDAO<T> {
public ObjectDAOMongoDBImpl(Class<T> entityClass, Mongo mongo, Morphia morphia, String dbName) {
super(entityClass, mongo, morphia, dbName);
}
}
Where, entityClass is provided at run-time - how can I use guice to bind the said type to an interface?
public class RunnerModule extends AbstractModule {
#Override
protected void configure() {
bind(GenericDAO.class).to(ObjectDAOMongoDBImpl.class);
}
}
public class Runner<T, V> {
GenericDAO<T, V> dao;
#Inject
public Runner(GenericDAO<T, V> dao) {
this.dao = dao;
}
public static void main(String[] args) {
Injector injector = Guice.createInjector(new RunnerModule());
injector.getInstance(Runner.class);
}
}
It's fine to define mongo, morphia, and dbName as literals to RunnerModule (is there a cleaner way?), but I have no way of knowing what entityClass is until runtime.
This isn't doable with Guice idiomatically, and it isn't its primary focus either.
jfpoilpret have said everything that can be said, but I would like to approach the problem from another direction, where you have the option to (possibly) solve your problem by losing type-safety.
So, in your code, you ask Guice to get an instance of your Runner<T, V> class like this
injector.getInstance(Runner.class);
but this can't be resolved by Guice, because Runner<T, V> has a dependency on GenericDAO<T, V>, but you didn't bind an exact implementation for it. So as jfpoilpret has said, you have to bind some concrete implementations for it in your module.
I'm guessing that you want to determine the exact GenericDAO<T, V> implementation that you pass to your Runner<T, V> based on some input data, which data's type isn't known at compile time. Now, let's assume you have two implementations.
bind(new TypeLiteral<GenericDAO<String, ObjectID>>(){}).to(StringDAO.class);
bind(new TypeLiteral<GenericDAO<Double, ObjectID>>(){}).to(IntegerDAO.class);
Based on different type of inputs you can do this
Injector injector = Guice.createInjector(new RunnerModule());
// possible input which you get from *somewhere* dynamically
Object object = 1.0;
TypeLiteral<?> matchedTypeLiteral = null;
for (Key<?> key : injector.getAllBindings().keySet()) {
TypeLiteral<?> typeLiteral = key.getTypeLiteral();
Type type = typeLiteral.getType();
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
if (parameterizedType.getRawType() == GenericDAO.class) {
List<Type> actualTypeArguments = Arrays.asList(parameterizedType.getActualTypeArguments());
if (actualTypeArguments.get(0) == object.getClass())
matchedTypeLiteral = typeLiteral;
}
}
};
Runner<?, ?> runner = new Runner<>((GenericDAO<?, ?>) injector.getInstance(Key.get(matchedTypeLiteral)));
System.out.println(runner.dao.getClass()); // IntegerDAO.class
If Object object = "string";, then the other implementation will be found. This is of course rather ugly and can be improved with checking for sub-classes and stuff, but I think you get the idea. The bottom-line is that you can't get around this.
If you manage to do it (getting around it), please drop me an e-mail because I would like to know about it! I had faced the same problem as you're facing not too long ago. I've written a simple BSON codec where I wanted to load specific implementations of a generic interface based on the type of some arbitrary input. This worked well with Java-to-BSON mappings, but I couldn't do it the other way around in any sensible way, so I've opted for a simpler solution.
The way you wrote it, entityClass can only be Object.class (== Class<Object>), and nothing else.
Hence, first of all, your ObjectDAOMongoDBImpl should be generic:
public class ObjectDAOMongoDBImpl<T>
extends GenericDAOMongoDBImpl<T, ObjectId> ...
That part of the problem is related to java, not Guice.
Now for Guice part, you need to define a binding including the generic types, ie by using Guice TypeLiteral:
bind(new TypeLiteral<GenericDAO<T, V>>(){}).to(...);
where T and V must be known in the code above (can't just be generic parameters there).
Looking at this question may also give you further details related to your situation.
This question is a bit old, but I've recently ran into a similar problem, and managed to solve it quite elegantly by adding a tiny extra layer, a factory.
Consider the following repository:
public interface Repository<T extends Model<T>> {
void save(T t);
T load(long key);
}
class SomeDbRepositoryImpl<T extends Model<T>> implements Repository<T> {
private final SomeDbConnection db;
private final Class<T> type;
RepositoryImpl(final Class<T> type, final SomeDbConnection db) {
this.db = db;
this.type = type;
}
...
}
Then, suppose I have a service that needs an instance of Repository<User>. My first try was to try to make Guice pass an instance of Repository<User> in the constructor, and then I'd bind it somehow. The problem is that I really don't want to have to add repository bindings and providers for each model. If I were to do that, the code would look like this:
// Won't work.
class MyService {
private final Repository<User> userRepository;
#Inject MyService(final Repository<User> userRepository) {
this.userRepository = userRepository;
}
...
}
What I ended up doing is creating a RepositoryFactory class, which is not generic by itself, but it contains a generic method.
public interface RepositoryFactory {
<T extends Model<T>> Repository<T> getRepository(Class<T> type);
}
class SomeDbRepositoryFactoryImpl implements RepositoryFactory {
private final SomeDbConnection db;
#Inject SomeDbRepositoryFactoryImpl(final SomeDbConnection db) {
this.db = db;
#Override <T extends Model<T>> Repository<T> getRepository(Class<T> type) {
return new SomeDbRepositoryImpl(type, db);
}
}
So, this is completely type-safe, and I don't have to add a binding for each module. The service that uses a Repository would then look like:
class MyService {
private final Repository<User> userRepository;
#Inject MyService(final RepositoryFactory f) {
this.userRepository = f.getRepository(User.class);
}
...
}
You could also keep the instance of RepositoryFactory instead of already getting the Repository instance.
I hope this can be useful to someone.
Beyond what Kohányi has said, you could load the DAO or entity classes reflectively by name, and then bind only the specific types asked for in the command-line arguments:
package com.example;
public class App
{
public static void main(final String[] args)
{
final Injector appleInjector = Guice.createInjector(new DynamicDaoModule(getClass("com.example.AppleDao")));
appleInjector.getInstance(Runner.class);
final Injector orangeInjector = Guice.createInjector(new DynamicDaoModule( getClass("com.example.OrangeDao")));
orangeInjector.getInstance(Runner.class);
// final Injector commandLineInjector = Guice.createInjector(new DynamicDaoModule(getClass(args[0])));
// commandLineInjector.getInstance(Runner.class);
}
private static Class getClass(final String className)
{
try
{
return Class.forName(className);
}
catch (final ClassNotFoundException e)
{
throw new RuntimeException(e);
}
}
}
class DynamicDaoModule extends AbstractModule
{
private final Class<? extends GenericDao<? extends Entity>> daoClass;
public DynamicDaoModule(final Class<? extends GenericDao<? extends Entity>> daoClass)
{
this.daoClass = daoClass;
}
#Override
protected void configure()
{
// bind GenericDao<? extends Entity> to daoClass
final TypeLiteral<GenericDao<? extends Entity>> daoOfEntity = (TypeLiteral) TypeLiteral.get(Types.newParameterizedType(GenericDao.class, Types.subtypeOf(Entity.class)));
bind(daoOfEntity).to(daoClass);
}
}
interface Entity
{
}
class Apple implements Entity
{
}
class Orange implements Entity
{
}
class Runner
{
#Inject
public Runner(final GenericDao<? extends Entity> dao)
{
System.out.println("This runner has an " + dao);
}
}
class GenericDao<T extends Entity>
{
private final Class<? extends Entity> entityClass;
protected GenericDao(final Class<? extends Entity> entityClass)
{
this.entityClass = entityClass;
}
#Override
public String toString()
{
return String.format("%s constructed with entityClass %s", getClass().getSimpleName(), entityClass.getSimpleName());
}
}
class AppleDao extends GenericDao<Apple>
{
#Inject
public AppleDao()
{
super(Apple.class);
}
}
class OrangeDao extends GenericDao<Orange>
{
#Inject
public OrangeDao()
{
super(Orange.class);
}
}
And the output would be
This runner has an AppleDao constructed with entityClass Apple
This runner has an OrangeDao constructed with entityClass Orange
I have changed the example to have entity classes implement an interface, in case they share some functionality that would be useful to Runner or GenericDao. If in fact you don't have such an interface, the technique also works with entity classes like String and Double if you remove the extends Entity upper bounds (e.g. GenericDao<T>).
I also removed the <T> parameter on Runner, as that was providing no benefit due to type erasure. If you were to subclass Runner<T>, then you might have Guice provide AppleRunner extends Runner<Apple> or OrangeRunner extends Runner<Orange>. But the type parameter provides nothing if Runner itself is the only concrete class Guice will be providing.
EDIT Oops, I left the class injections in. They are removed now. Of course, if you have a concrete GenericDao subclass for each entity, then perhaps you don't need to inject the entity classes themselves.
I suppose it's not clear to me whether you can provide concrete GenericDao subclasses for all the entity types ahead of time or not. If not, and you were only using the GenericDao class itself for each different kind of entity class, then you would want to inject concrete entity classes and not concrete DAO classes.

Categories

Resources