Call generic type instance method - java

I have implemented Generic DAO for all my bean classes. I am facing a problem in setting the entries in to the cache.
DAO.class
public abstract class DAO<T extends Serializable> extends Cache
{
save(Collection<T> list)
{
// batch process will store the list to db
for(T t : list)
{
cache(t.getKey(), t);
}
}
}
Bean's DAO classes
public class BeanDAO1 extends DAO<Bean1>
{
public static set(Collection<Bean1> list)
{
super.save(list);
}
}
public class BeanDAO2 extends DAO<Bean2>
{
public static set(Collection<Bean2> list)
{
super.save(list);
}
}
Now the problem is, both Bean classes have same getter method getKey(). But in DAO class, as it is type referenced, i couldn't access the method.
Is it something i am doing wrong or I should do some other thing?

In your save method you access the method getKey() on objects of type T. For that you must constrain that type variable to be a subtype of a type that has this method. As it is, the only thing the compiler know that your T is a subtype of Serializable (which doesn't have this method).
That means you should have a supertype for all your beans:
public interface Bean extends Serializable {
public ? getKey(); // I do not know what type your keys are
}
Your bean classes should implement this interface. Then you can do the following:
public abstract class DAO<T extends Bean> extends Cache {
public save(Collection<T> list) {
for(T t : list) {
cache(t.getKey(), t);
}
}
}

Your type declaration T extends Serializable is too broad. You must define a class implementing or an interface extending Serializable that has an abstract method getKey() and let T extend this new type.

The cleanest solution as #Ray suggested is having a common interface for Entity classes such as:
public abstract class DAO<T extends AbstractEntity> extends Cache
{
save(Collection<T> list)
{
// batch process will store the list to db
for(T t : list)
{
cache(t.getKey(), t);
}
}
}
And the interface:
public interface AbstractEntity
{
}
EDIT:
And having Bean1 and Bean2 implement the interface as such:
public class Bean1 implements AbstractEntity
{
}
public class Bean2 implements AbstractEntity
{
}

The marker interface Serializable doesn't define getKey() method.However,your type T can declare multiple upper bounds.Let your Bean1 and Bean2 extend a common super class or inteface which has a getKey() method
interface Bean{
Object getKey();
}
class Bean1 implements Bean,Serializable {
public String getKey(){
///
}
}
class Bean2 implements Bean,Serializable{
public String getKey(){
///
}
}
public abstract class DAO<T extends Bean & Serializable> extends Cache
{
save(Collection<T> list)
{
// batch process will store the list to db
for(T t : list)
{
cache(t.getKey(), t);
}
}
}
public class BeanDAO1 extends DAO<Bean1>
{
public static set(Collection<Bean1> list)
{
super.save(list);
}
}
public class BeanDAO2 extends DAO<Bean2>
{
public static set(Collection<Bean2> list)
{
super.save(list);
}
}

Related

Generic method, generic type unknow

I have many bean i would like to convert to Dto
In every class, i do something like
private List<AddressDto> convertsToDto(List<Address> addresses) {
List<AddressDto> addressesDto = new ArrayList<>();
addresses.stream().map((address) -> convertToDto(address)).forEachOrdered((addressDto) -> {
addressesDto.add(addressDto);
});
return addressesDto;
}
convertToDto would be in every class.... but for convertsToDto i will put in t a abstract class where every class will extends it and put a generic convertsToDto method with generic type
public abstract class BaseService {
public List<T> convertsToDto(List<R> beans) {
List<T> listDto = new ArrayList<>();
beans.stream().map((bean) -> convertToDto(bean)).forEachOrdered((dto) -> {
listDto.add(dto);
});
return listDto;
}
}
I always get T and R is unknown... seem to miss something.
Start with adding T and R type parameters to your generic method. However, this will not do the trick, because convertToDto(bean) would remain undefined.
You have several options here:
You could define bean interface to produce its DTO, or
You could pass a bean-to-DTO function object.
Here is the first approach:
interface Bean<T> {
T convertToDto();
}
public abstract class BaseService {
public <T,R extends Bean<T>> List<T> convertsToDto(List<R> beans) {
return beans.stream().map((b) -> b.convertToDto()).collect(Collectors.toList());
}
... // Additional methods
}
Here is the second approach:
public abstract class BaseService {
public <T,R> List<R> convertsToDto(List<T> beans, Function<T,R> convert) {
return beans.stream().map((b) -> convert.apply(b)).collect(Collectors.toList());
}
}
Your BaseService class does not define these generic types.
Try
public abstract class BaseService<T, R> {
...
}
public class AddressService extends BaseService<AddressDto, Address> {
...
}
You can have a generic interface like Dto<T> for this to work.
And you will be able to have your generic convertion method to look like this:
public <T extends Dto<R>> List<T> convertsToDto(List<R> beans) {
}
Your Dto objects will be implementing the interface mapping them to the base object.

Get actual enum class of the Parameterized class T extends Enum<?>

I have a class:
public class MultipleSorting<T extends Enum<?>> {
private T criteriaType;
public Class<T> getCriteriaClass() {
Field field = ReflectionUtils.getField(getClass(),"criteriaType");
ReflectionUtils.makeAccessible(field);
return (Class<T>)field.getType();
}
}
This class is get instantiated as:
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?,?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController() {
super();
multipleSorting = new MultipleSorting<U>();
}
}
The actual value of U is passed from the child class of MultiSortPageableController which is:
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T,ArticleSortField> {
}
The ArticleSortField is an Enum.
I was expecting the method getCriteriaClass of MultipleSorting would return ArticleSortField from a method of MultiSortPageableController. But it is returning java.lang.Enum.
I am unable to figure it out why it is not returning the actual enum and how can I make it so. Any pointer would be very helpful to me. I need to get ArticleSortField.
Purpose:
I two requirement:
To get the actual class of enum type (say ArticleSortField.class)
To list enum value. If I have the enum class, then I could invoke class..getEnumConstants().
Java compiler removes information about generics, therefore when you use reflection you get no information about the declared type, other than Enum. This process is called type erasure.
How about passing the type down, via the constructor, like this:
public class MultipleSorting<T extends Enum<?>> {
private Class<T> criteriaType;
MultipleSorting(Class<T> criteriaType) {
this.criteriaType = criteriaType;
}
public Class<T> getCriteriaClass() {
return criteriaType;
}
}
public abstract class MultiSortPageableController<T extends MultiSortPageableController<?, ?>, U extends Enum<?>> {
private MultipleSorting<U> multipleSorting;
public MultiSortPageableController(Class<U> criteriaType) {
super();
multipleSorting = new MultipleSorting<U>(criteriaType);
}
}
public abstract class AbstractArticleSearchController<T extends AbstractArticleSearchController<T>> extends MultiSortPageableController<T, ArticleSortField> {
public AbstractArticleSearchController() {
super(ArticleSortField.class);
}
}

Initiating instance variables in a class that extends a generic class

I have a generic class "SimpleList" (excerpt):
public abstract class SimpleList<T> {
protected List<T> list;
public SimpleList(List<T> list) {
this.list = list;
}
}
And another class "TrackList" that extends it (excerpt):
public class TrackList extends SimpleList {
public TrackList(List<XmlTrack> list) {
super(list);
}
}
In "TrackList" I specify that the list is to hold objects of type "XmlTrack". It seems though, like it's not possible to get an object from that list and access its methods. For example, this won't work:
list.get(0).someMethodSpecificToXmlTrack()
I don't understand why this doesn't work? Isn't the list in "SimpleList" set to only hold "XmlTrack"s?
You need to define it as
public class TrackList extends SimpleList<XmlTrack> {
public TrackList(List<XmlTrack> list) {
super(list);
}
}
Because SimpleList is generic, but you did not specify a type argument when you extended it.
May be you need
public class TrackList extends SimpleList<XmlTrack>

Generics: generic class based on generic class

I'm trying to create a generic service that is based on a class with a generics based collection
public class GenericClass<T> {
List<T> results;
public List<T> getResults() {
return results;
}
}
Im just not sure how to create a service that is based on this GenericClass and has a concrete implementation of T. I would expect something like
public class ServiceManagerImpl<GenericClass<T>> implements ServiceManager<GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
But the compiler doesn't like this. Any ideas how to do this?
Marc
You are close... just pass the T through:
public class ServiceManagerImpl<T> implements ServiceManager<GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
I can suggest the following implementation that doesn't break the rules of JLS:
// ServiceManager.java
public interface ServiceManager<E, T extends GenericClass<E>> {
}
// ServiceManagerImpl.java
public class ServiceManagerImpl<E, T extends GenericClass<E>> implements ServiceManager<E, T> {
public T getMyClass() {
return null;
}
}
The content between <> is called Type Parameters, and GenericClass<T> is not a valid Type Parameter in declaration.
Quote from java generic guide
A generic class is defined with the following format:
class name<T1, T2, ..., Tn> { /* ... */ }
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, ..., and Tn.
so, you need to use GenericClass<T> in implementation, not in declaration.
// declaration
public class ServiceManagerImpl<YourGenericType> implements ServiceManager<YourGenericType> {
public YourGenericType getMyClass() {
...
}
}
// implementation
ServiceManager<GenericClass<Object>> sm = new ServiceManagerImpl<GenericClass<Object>>();
public class ServiceManagerImpl<T extends GenericClass<T>> implements ServiceManager<T extends GenericClass<T>> {
public GenericClass<T> getMyClass() {
...
}
}
I am not sure my answer is legal , but it seems meet your requirement:
public class ServiceManagerImpl<T extends GenericClass> implements ServiceManager<T>
{
#Override
public T getMyclass() {
//do your work here;
}
}
Although it may have a unchecked warning when I declare this class , but this really does!
ServiceManager<GenericClass<Integer>> manager = new ServiceManagerImpl<GenericClass<Integer>>();//passed
You should try likes this;
public class ServiceManagerImpl<GenericClass<Object>> implements ServiceManager<GenericClass<Object>> {
public GenericClass<Object> getMyClass() {
...
}
}
You can replace Object with Integer or String or any data types as you likes.

How to convert implementors on one interface into another?

I'm having trouble finding a way to do this in a way that doesn't seem wrong, given the following
public interface IType {}
public interface IMode {}
public interface Factory<T extends IType> {
IMode get(T o);
Class<T> getIType();
}
I have the above interfaces and a large list on classes the implement both IType and IMode with corresponding factories.
I need to be able to convert from one to the other, for example,
public class A implements IType {}
public class One implements IMode {}
public class AToOne implements Factory<A> {
public IMode get(A o){
return new One();
}
public Class<A> getIType(){
return A.class;
}
}
Given that there is a 1 to 1 mapping of these classes, ie for every concrete IType there is one and only one concrete IMode with corresponding factory, how would I go about converting a list of ITypes to a list of IModes?
ie.
private List<Factory<? extends IType>> factoryList;
public List<IMode> getConversions(List<? extends IType> types){
???
}
My first try did not go so well,
//Fill this using the getIType() method from each factory
Map<Class<IType>, Factory<? extends IType>> factoryList = new HashMap<Class<IType>, Factory<? extends IType>>();
public List<IMode> getConversions(List<IType> types){
List<IMode> modes = new ArrayList<IMode>();
for(IType type : types){
//Derp
Factory<? extends IType> factory = factoryList.get(type.getClass());
//Error
factory.get(factory.getIType().cast(type));
}
}
Error:
The method get(capture#12-of ? extends IType) in the type
Factory<capture#12-of ? extends IType>
is not applicable for the arguments (capture#14-of ? extends IType)
Like I mentioned in my comment, you just need to use a generic helper method to access the map, which performs an unchecked cast from Factory<? extends IType> to a Factory<T> where T matches the type of what's passed in:
Map<Class<? extends IType>, Factory<? extends IType>> factoryList =
new HashMap<Class<? extends IType>, Factory<? extends IType>>();
private <T extends IType> IMode convert(T iType) {
//unchecked cast - implementation must guarantee map holds correct data
Factory<T> factory = (Factory<T>)factoryList.get(iType.getClass());
//then convert
return factory.get(iType);
}
You can call this helper method from the loop:
public List<IMode> getConversions(List<IType> types) {
List<IMode> modes = new ArrayList<IMode>(types.size());
for (IType type : types) {
IMode iMode = convert(type);
modes.add(iMode);
}
return modes;
}
The simple solution is the following:
interface IFoo {
}
interface IBar {
}
private static class Foo implements IFoo {
}
private static class Bar implements IBar {
}
interface IFoo2IBarConverter<B extends IBar, F extends IFoo> {
B convert(F foo);
}
private static class Foo2BarConverter implements IFoo2IBarConverter<Bar, Foo> {
public Bar convert(Foo foo) {
return new Bar();
}
}
private static class IFoo2IBarFactory {
private static HashMap<Class<? extends IFoo>, IFoo2IBarConverter<? extends IBar, ? extends IFoo>> converters = new HashMap<>();
static {
converters.put(Foo.class, new Foo2BarConverter());
}
public static<F extends IFoo, B extends IBar> B convert(F foo) {
// ugly unchecked cast here
IFoo2IBarConverter<B, F> converter = (IFoo2IBarConverter<B, F>) converters.get(foo.getClass());
return converter.convert(foo);
}
}
public static void main(String[] args) {
Foo foo = new Foo();
IBar bar = IFoo2IBarFactory.convert(foo);
}
You just take a HashMap that maps a specific class that's a subtype of IFoo to some converter interface. The converter takes the IFoo instance and converts it into a IBar.. actually into the specific classes we want. Sadly we get an ugly cast in IFoo2IBarFactory.convert() and I don't think there's any way to avoid that one. Still at least it's only in one localized position and with the right comment and a SuppressWarning you can live with it, I'd think

Categories

Resources