How to use Java generics for calling method with dynamic parameter? - java

I have 2 objects, user and userevent... And I have set of 7 methods common for both.. User and userevent are different objects with few matching parameters..
How to implement this with generics so that I can reuse the methods for both user and userevents ?? Method accept user or userevent or both object as parameter..

Why not use an interface?
Both User and UserEvent classes would implement this interface. Common methods would be declared in the Interface and overriden in both classes.
As for the methods, they would accept as parameters any object that implements the newly created Interface.

If I understood you correctly, kindly check my example written for dao object
public interface IDao<T> {
void saveOrUpdate(T instance);
Long save(T instance);
void delete(T instance);
T get(Long id);
}
public class BasicHibernateDao<T> extends HibernateDaoSupport implements IDao<T> {
private final Class<T> clazz;
public BasicHibernateDao(Class<T> clazz) {
this.clazz = clazz;
}
public void saveOrUpdate(T instance) {
getHibernateTemplate().saveOrUpdate(instance);
}
public Long save(T instance) {
return (Long) getHibernateTemplate().save(instance);
}
public void delete(T instance) {
getHibernateTemplate().delete(instance);
}
public T get(Long id) {
return getHibernateTemplate().get(clazz, id);
}
}
public class ClientDao extends BasicHibernateDao<Client> {
public ClientDao() {
super(Client.class);
}
}
Hope that this analogy would be helpful for you

Related

Java generics both methods have same erasure error

In my project, I have multiple services performing three basic operations - create, edit and search. For this, I am trying to create a generic service. Below is what I have come up with so far.
Search method will take a list of objects at runtime.
public interface GenericService<T> {
void update(T t);
void create(T t);
T search(List<?> t);
}
Also, I have created an abstract class where the common code for all services will be placed.
public abstract class AbstractService<T> implements GenericService<T> {
}
Here is my implementation
public class AccountService extends AbstractService<Account> implements GenericService<Account> {
#Override
public void update(Account account) { }
#Override
public void create(Account account) { }
#Override
public Account search(List<SearchCriteria> t) { return null; }
}
Here are my Account and SearchCriteria classes
public class Account {
private String accountNumber;
private Date openingDate;
// more fields
// getter setter removed for brevity
}
Search criteria class
public class SearchCriteria {
private String key;
private String value;
// getter setter removed for brevity
}
Problem: on line public Account search(List t) { return null; }, getting compilation error saying
'search(List)' in
'com.test.AccountService' clashes with
'search(List)' in 'com.test.GenericService';
both methods have same erasure, yet neither overrides the other
In order for
public Account search(List<SearchCriteria> t) { ...}
to override
T search(List<?> t);
The arguments must be the same after type parameter substitution, but ? is not SearchCriteria.
Therefore, if you want to keep these methods (the inheritance looks a bit wild to me), you'll need to parameterise the types further.
public interface GenericService<T, C> {
// ...
T search(List<C> t); // probably change that parameter name
}
public abstract class AbstractService<T, C>
implements GenericService<T, C>
{
}
public class AccountService
extends AbstractService<Account, SearchCriteria>
implements GenericService<Account, SearchCriteria> // unnecessary
{
// ...
#Override
public Account search(List<SearchCriteria> t) { /* ... */ }
}
Changing List<?> to List<SearchCriteria> in GenericService will solve the error. There is no benefit in using a wildcard if the search method will always take a list of SearchCriteria objects in every service implementation.
If, however, you want to make this generic as well, you can introduce a second type parameter.

How to make an interface extends its own generic type

I would like to create a contract (an interface), with a generic parameter, which enforces that the implemented class must also be the type specified in the generic parameter.
public interface SelfDefaultAlternativeDetailSupport<T extends AlternativeDetail> extends T { // syntax error (extends T)
default T resolveDetail() {
if (someConditions()) {
return this;
} else {
return getAlternativeDetails().stream()
.filter(somePredicate)
.findFirst().orElse(null);
}
}
List<T> getAlternativeDetails();
}
Example Usage
public interface CustomerDetail extends AlternativeDetail {
String getName();
}
public class Customer implements SelfDefaultAlternativeDetailSupport<CustomerDetail>, CustomerDetail {
#Override
public String getName() {
return "default name";
}
#Override
public List<AlternativeDetails> getAlternativeDetails() {
...
}
}
In other words, I would like that when a class implements SomeInterface<X>, the class must also implement X, But the attempt above has syntax because I cannot make SelfDefaultAlternativeDetailSupport extends T. Is this possible in Java?
You can make it a self-referential generic type:
public interface SelfDefaultAlternativeDetailSupport<T extends SelfDefaultAlternativeDetailSupport<T> & AlternativeDetail> {
#SuppressWarnings("unchecked")
default T resolveDetail() {
if (someConditions()) {
return (T) this;
} else {
return getAlternativeDetails().stream()
.filter(somePredicate)
.findFirst().orElse(null);
}
}
List<T> getAlternativeDetails();
}
Then you can have:
public class Customer implements SelfDefaultAlternativeDetailSupport<Customer>, CustomerDetail {
#Override
public List<Customer> getAlternativeDetails() {
...
}
}
Just be careful to never use a different class as the parameter to SelfDefaultAlternativeDetailSupport. If you want to avoid the unchecked cast of this, you can use getThis methods, but I don't think it's really worth it.

GenericDAO and ClassCast

I've wrote the following GenericDAO as in the code below
abstract public class DAO <T extends AbstractBusinessObject> {
// CRUD: create, read, update, delete
public abstract T create(Class<T> abObj);
public abstract T read();
public abstract void update(T abObj);
public abstract void delete(T abObj);
}
Also I have implemented some commands via Command Pattern which interact with DAOInMemory extending GenericDAO in order to perform tasks like "register user name password".
public class RegisterUserCommand extends AbstractCommand {
public RegisterUserCommand() {
...
}
...
#Override
public void execute(String[] cmdArgs) {
// class cast here
User userObject = (User) daoInstance.create(User.class);
//why doesn't this work?
//User userObject = daoInstance.create(User.class);
}
}}
I don't understand why I have to cast result of the daoInstance.create(User.class) when DAOInMemory has already cast operation in create-method?
public class DAOInMemory<T extends AbstractBusinessObject> extends DAO<T> {
...
public DAOInMemory() {
...
public T create(Class<T> abstractObjectType) {
IDGenerator IDGenerator = IDGenerator.getInstance();
if (User.class.isAssignableFrom(abstractObjectType)) {
BigInteger id = IDGenerator.getID();
User user = new User(id);
return (T) user;
}
Could you explain this behaviour of Java?
EDIT: I forgot to add that public class User extends AbstractBusinessObject
You must be avoiding the use of Generics when you instantiate your DAO class.
Example 1: (Requires a cast):
DAO dao = new DAOInMemory();
User user = (User) dao.create(User.class);
Example 2: (Does not require a cast):
DAO<User> dao = new DAOInMemory<User>();
User user = dao.create(User.class);
You need to Cast because T is not necessarily User.
In fact, this code might cause class cast exception, since your generic definitions is T extends AbstractBusinessObject which does not imply User

Setting return type of method to type of calling object

I have a method defined as follows:
public TYPE getById(ObjectId id) {
return datastore.get(this.getClass(), id);
}
The method signature of datastore.get() is:
<T, V> T get(Class<T> var1, V var2);
How would I properly set the return type of my method? Note that the object returned by datastore.get() is not the same type as my implementing class, it can be a subclass. Therefore I want the return type to be specific to that class.
What I understand is you want something like this:
public class Factory<T> {
public T getById(ObjectId id) {
return datastore.get(T, id);
}
}
public class Class1Factory extends Factory<Class1> {
public Class1 getById(ObjectId id) {
return datastore.get(Class1.class, id);
}
}
You have to use separate Factory classes as you cannot parameterize a class to itself. You cannot say:
public class Class1 extends Parent<Class1> {
...
}

Abstracting named queries in an abstract JPA DAO

I have an abstract DAO class which uses parameterized types E (Entity) and K (Primary Key). In every entity I have a #NamedQuery. I want to dynamically invoke this named query without knowing its exact name and parameter name.
As an example, imagine the following entity City
#Entity(name="CITY")
#NamedQuery(
name="findCityByname",
query="FROM CITY c WHERE name = :CityName"
)
public class City {
// ...
}
and this CityDao
public class CityDao extends AbstractDao<City, Long> {
public CityDao() {
super(City.class);
}
}
How should I implement the findByName() method in AbstractDao so that I don't need to know the exact name and parameter name?
public abstract class AbstractDao<E, K> implements Dao<E, K> {
#PersistenceContext
protected EntityManager entityManager;
protected Class<E> entityClass;
protected AbstractDao(Class<E> entityClass) {
this.entityClass = entityClass;
}
#Override
public E findByName(String name) {
try {
return (E) entityManager
.createNamedQuery("findCityByName")
.setParameter("CityName", name)
.getSingleResult();
} catch(Exception e) {
return null;
}
}
// ...
}
The naming convention for named queries is usually <Entity Name>.findBy<PropertyAndAnotherProperty>, "City.findByName" in your example, so I would try to change the named queries to follow this pattern. The parameter to this query should then also have the same name, or you could use positional parameters. Your find method would then turn into
#Override
public E findByName(String name) {
E entity = null;
try {
return (E)entityManager.createNamedQuery(myClass.getSimpleName() + ".findByName")
.setParameter("name", name)
.getSingleResult();
} catch (Exception ex) {
return null;
}
}
The simplest method is to pass the name of the query to the constructor of the abstract DAO:
public DaoAbstreact(Class myClass, String findByNameQueryName) {
this.myClass = myClass;
this.findByNameQueryName = findByNameQueryName;
}
Then define a public static final String in City to hold the name:
public class ConcreteCityDao<City,Long> extends DaoAbstreact {
ConcreteCityDao(){
super(City.class, City.FIND_BY_NAME_QUERY_NAME));
}
}
Alternatively you could declare DaoAbstreact as abstract and then have a method like this in it:
public abstract String getFindByNameQueryName();
And implement that in ConcreteCityDao.
Finally you could also introduce an enumeration:
public enum NamedEntityType {
CITY(City.class, "findCityByname"),
PERSON(Person.class, "findPersonByname");
private final Class<?> entityClass;
private final String findByNameQueryName;
private NamedEntityType(Class<?> entityClass, String findByNameQueryName) {
this.entityClass = entityClass;
this.findByNameQueryName = findByNameQueryName;
}
public Class<?> getEntityClass() {
return entityClass;
}
public String getFindByNameQueryName() {
return findByNameQueryName;
}
}
Then your DAO can determine the type from the class passed in. To ensure you don't forget to add an entity to the enumeration you can make each entity implement an interface with a getNamedEntityType() method. Then you can specify that your abstract generic DAO will only accept entities that implement that interface.
The obvious way would be to pass values from concrete classes to the abstract superclass using abstract method
public abstract class AbstractDao<E, K extends Serializable> implements Dao <E, K> {
...
protected abstract String getFindByNameQueryName();
#Override
public E findByName(String EntityStr) {
... entityManager.createNamedQuery(getFindByNameQueryName()) ...
}
}
#Override
public class ConcreteCityDao<City,Long> extends DaoAbstreact{
...
protected String getFindByNameQueryName() {
return "findCityByName";
}
}
or as a constructor argument:
public abstract class AbstractDao<E, K extends Serializable> implements Dao<E, K> {
public AbstractDao(Class<E> myClass, String findByNameQueryName) { ... }
...
}
#Override
public class ConcreteCityDao<City, Long> extends DaoAbstreact{
public ConcreteCityDao() {
super(City.class, "findCityByName");
}
}
Though this requires consistent naming of query parameters for different entities.
Also note the minor improvements in these snippets.
What you basically seem to want is to annotate the annotations that define the named queries, in such a way that you can programmatically discover what the "findByName" query is (and possible other queries).
Since this is not possible in Java, you could use the fact that #NamedQuery supports query hints, that are defined as being vendor specific. Unknown hints are ignored. You could add your own data here, that the generic DAO can read back from entityClass:
#NamedQuery(
name="findCityByname",
query="FROM CITY c WHERE name = :CityName",
hints=#QueryHint(name="genericDAO.type", value="findByName")
)

Categories

Resources