GenericDAO and ClassCast - java

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

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.

Java abstract class to get type of extended class

I don't how to phrase this, so I'll drop an example
class AbstractUser<A extends AbstractAccount<? extends AbstractType>> {
// I want a method that has access to Type
// And returns the specific Type that extends AbstractType
protected <T extends AbstractType> T doSomething(T type) {
// do stuff
// and return the type specific type T
}
}
class AbstractAccount<T extends AbstractType> {
}
class AbstractType {
}
class Type extends AbstractType {
}
class Account extends AbstractAccount<Type> {
}
class AccountAdmin extends AbstractAccount<Type> {
}
class User extends AbstractUser<Account> {
}
What I want in this is that within User class I can do getType() and it returns the the specific type of AbstractAccount, in this case Account.
How do I do this without specifying any more templates? In other words, I want whatever type the ? in ? extends AbstractType is to be in that method
So if I do
final Account account = ...
final AccountAdmin admin = ...
final User user = ...
user.doSomething(account); // should work
user.doSomething(AccountAdmin); // should fail
You obviously can't create a method in AbstractUser like this:
public Class<A> getType() { return A.class; }
This is because of type erasure. The runtime does not know what A is.
So one workaround is to make this method abstract:
public abstract Class<A> getType();
Now, you can implement this method in subclasses:
class User extends AbstractUser<Account> {
public Class<Account> getType() { return Account.class; }
}
EDIT:
Now I realised you want the type that extends AbstractType, the workaround should still work. You just need to create another getType in AbstractAccount and make Account implement that method.
You can't really get around binding another type parameter in AbstractUser for this purpose:
class AbstractUser<T extends AbstractType, A extends AbstractAccount<T>> {
protected abstract T getType();
}
You need a way to reference the type of A's type parameter, and this serves that purpose.
As of Java 8 you could define a constructor which takes a Supplier returning instances of the appropriate type.
You said:
What I want in this is that within User class I can do getType() and it returns the the specific type of AbstractAccount, in this case Account.
And you want: doSomething(T type).
Thus I assume, you don't want a Class<T> but an instance of T to work with. As of your example this T should be Account.
According to this:
class AbstractUser<T extends AbstractType, A extends AbstractAccount<T>> {
private Supplier<T> accountSupplier;
public AbstractUser(Supplier<T> accountSupplier) {
this.accountSupplier = accountSupplier;
}
protected T getType() {
return accountSupplier.get();
}
}
Then class User would look as follows:
class User extends AbstractUser<Type, Account> {
public User() {
super(Account::new);
}
}
Please note that the class AbstractUser is still not declared abstract. If the only reason to have this class is providing different types of AbstractAccount by subclasses, then now we can do it without subclasses.
User user = new User(); can be rewritten as AbstractUser user = new AbstractUser(Type::new); (in this case AbstractUser is not the best name).

How do I make a class extending another extended class work with generic collections?

In our current codebase, we have the following data structure to communicate between our service layer and our frontend layer:
public class BaseView {
private Integer id;
// Other common attributes and getters/setters;
}
public class BarView extends BaseView {
private String name;
private String Description;
// Other attributes for this object and getters/setters;
}
We also have a number of double extended classes:
public class BazView extends BaseView {
// name, description, other common attributes;
}
public class BazTypeAView extends BazView {
// attributes specific to Type A Baz;
}
public class BazTypeBView extends BazView {
// attributes specific to Type B Baz;
}
In our service layer, we have service methods implementing a BaseService: a BarService, a BazService, a BazTypeAService, a BazTypeBService and other with a similar naming scheme which all have methods returning either the class they're responsible for, or a List<class they are responsible for>. In turn, each of these methods calls a method from the BaseService with signature GetObjects(Class Viewtype, Class BeanType, Criteria), with the criteria based on parameters passed into the specific method method. the Beans are between the Service Layer and the Data Access Layer and not really relevant to this.
An example of the scheme:
public interface BaseService {
public BaseView getObject(Class viewType, class beanType, Integer id);
public List<BaseView> getObjects(Class viewType, class beanType, Criteria criteria);
}
public class BaseServiceImpl implements BaseService {
protected BaseView getObject(Class viewType, class beanType, Integer id){
BaseBean bean = (BaseBean) DataService.getobject (beanType, id);
BaseView view = ViewGenerator.createEmptyView(viewType);
copyAttributes(bean, view);
return view;
}
protected List<BaseView> getObject(Class viewType, class beanType, Criteria criteria){
List<BaseBean> bean = (List<BaseBean>) DataService.getobject (beanType, Criteria);
List<BaseView> view = new ArrayList<BaseView>();
copyAttributes(bean, view);
return view;
}
}
public interface BarService extends BaseService {
public BarView getBar(Integer id);
public List<BarView> getBars(BarView barView);
}
public class BarServiceImpl extends BaseServiceImpl implements BarService {
public BarView getBar(Integer id){
BarView bar = getObject(BarView.class, BarBean.class, id);
return bar;
}
public List<BarView> getBars(BarView barView){
Criteria criteria = getCriteriaFromBarView(barView);
List<BarView> bars = getObjects(BarView.class, BarBean.class, criteria);
return bars;
}
}
The above is roughly how the system works. The methods to create a Bar, get a list of Bars, update a Bar and delete a Bar all are effectively the same as the above.
the problem is that getObject returns a raw List, leading to a lot of Eclipse warnings and code that's harder to read. over 2/3 of our warnings for this project are about raw type usage, and though our code still compiles and works as it should, it's A LOT of messages.
If we didn't have the second kind of View which extends an extended class, we could just do List<? extends Fooview>, but that gives errors for the classes extending BazView. Is there a way to make generic types work here when you have both ? extends Baseview and ? extends X extends Baseview?
My answer does not differ much from the others, except that I guess your BaseService is an interface:
In our service layer, we have service methods implementing a BaseService
I would define the interface like that(EDIT):
public interface BaseService<T extends FooView>{
T getObject(Class<T> viewType, Class<? extends FooBean> beanType, Integer id);
List<T> getAllObjects(Class<T> viewType, Class<? extends FooBean> beanType);
}
(ADDED)
Implementing that interface in an abstract class requires that all depending services use generics as well:
public abstract class BaseServiceImpl<T extends FooView> implements BaseService<T>{
#Override
public T getObject(Class<T> viewType, Class<? extends FooBean> beanType, Integer id){
FooBean bean = DataService.getObject(beanType, id);
T view = ViewGenerator.createEmptyView(viewType);
copyAttributes(bean, view);
return view;
}
#Override
public List<T> getAllObjects(Class<T> viewType, Class<? extends FooBean> beanType){
List<? extends FooBean> beanList = DataService.getAllObjects(beanType);
return beanList.stream().map(bean -> {
T view = ViewGenerator.createEmptyView(viewType);
copyAttributes(bean, view);
return view;
}).collect(Collectors.toList());
}
private void copyAttributes(FooBean bean, T view){}
}
(EDIT)
The implementation of all your services should be straight forward then:
public class BarServiceImpl extends BaseServiceImpl<BarView> implements BarService{
#Override
public BarView getBar(Integer id){
return getObject(BarView.class, BarBean.class, id);
}
#Override
public List<BarView> getAllBars(){
return getAllObjects(BarView.class, BarBean.class);
}
}
public class BazServiceImpl extends BaseServiceImpl<BazView> implements BazService{
#Override
public BazView getBaz(Integer id){
return getObject(BazView.class, BazBean.class, id);
}
#Override
public List<BazView> getAllBazs(){
return getAllObjects(BazView.class, BazBean.class);
}
}
public class BazTypeAServiceImpl extends BaseServiceImpl<BazTypeAView> implements BazTypeAService{
#Override
public BazTypeAView getBazTypeA(Integer id){
return getObject(BazTypeAView.class, BazTypeABean.class, id);
}
#Override
public List<BazTypeAView> getAllBazTypeAs(){
return getAllObjects(BazTypeAView.class, BazTypeABean.class);
}
}
At least in my main method there are no warning because everything is cleanly typed:
public class Main{
public static void main(String[] args){
BarService barService = new BarServiceImpl();
BarView barView = barService.getBar(111);
List<BarView> barViewList = barService.getAllBars();
BazService bazService = new BazServiceImpl();
BazView bazView = bazService.getBaz(222);
List<BazView> bazViewList = bazService.getAllBazs();
BazTypeAService bazTypeAService = new BazTypeAServiceImpl();
BazTypeAView bazTypeAView = bazTypeAService.getBazTypeA(333);
List<BazTypeAView> bazTypeAViewList bazTypeAService.getAllBazTypeAs();
}
}
NOTE:
Replacing the interface with an abstract class(if possible) would reduce the code again because both of the sample methods could be implemented in the abstract class. The main method wouldn't need to change at all.
EDIT
You need to use generics also at that level where you create your objects. Otherwise you need a lot of casting and you get those ugly warnings with your lists. I updated my sample for you.
EDIT2
I already mentioned it before that your DataService and your ViewGenerator need to use generics too. This is how I would implement the method bodies:
public class DataService {
public static <T extends FooBean> T getObject(Class<T> beanType, Integer id){return null;}
public static <T extends FooBean> List<T> getAllObjects(Class<T> beanType){return null;}
}
public class ViewGenerator {
public static <T> T createEmptyView(Class<T> viewType){return null;}
}
if I understand you correctly, what you need is to make your BaseService get a generic type that will be used in the getObject method:
BaseService class:
public class <T extends FooView> BaseService<T> {
public T getObject() {
...
}
}
and in the specific services:
public class BazTypeAService extends BaseService<BazTypeAView> {
...
}
A quick answer to use the code styling, I will delete it if I didn't not understand well.
Try to use a generic type like this :
public abstract class BarService<T extends FooView>{
List<T> list;
...
public List<T> getList(){ return list;}
}
public class BazService extends BarService<BazView>{
...
}
public class BazTypeBService extends BarService<BazTypeBView>{
...
}
...
Here,
BazService.getList() will return a List<BazView> instance
BazTypeBService .getList() will return a List<BazTypeBView> instance

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

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

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