Generic method, generic type unknow - java

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.

Related

Casting to unbound generics in Java

I've got the following java pseudocode
public interface JobData {}
public class JobStatus<T extends JobData> {
public T jobData;
}
public class A implements JobData {}
public class B extends A {}
public class C extends A {}
public class Service {
private Map<Long, JobStatus> jobStatusMap;
public <T extends JobData> List <JobStatus<T>> getJobsByJobDataType(Class<T> clazz)
{
return jobStatusMap.values().stream()
.filter(js -> clazz.isInstance(js.getJobData()))
.map((js) -> (JobStatus<T>) js) // HERE
.collect(Collectors.toCollection(ArrayList::new));
}
}
But I'm having trouble with the line marked "HERE". Essentially, I've got an map of JobStatus objects, each of which has a field, jobData, which is a generic implementing the interface JobData. I want to get all the JobStatus items whose jobData field is a subclass of class of say, class A:
List<JobStatus<A>> jobStatuses = getJobsByJobDataType(A.class);
How do I, I guess at compile-time, cast my JobStatus objects to JobStatus<T>?
I can do a dynamic cast in a number of ways via things like myClass.cast(js), but I'm not sure how to do that if myClass is a generic JobStatus<T> where T is bound or alternatively defined in clazz.
It seems you're attempting to cast elements to a type that is different from the list type. In other words, your return signature is of type List<JobStatus<T>> where JobStatus does not extend JobData, although you're trying to cast each assignable element to the type JobData.
Is this what you want to do?
public interface JobData<T> {
T getData();
}
public interface JobStatus<T extends JobData> {
T getJobData();
}
public class Service {
private Map<Long, JobStatus> jobStatusMap;
public <T extends JobData> List<JobStatus<T>> getJobsByJobDataType(Class<T> clazz) {
return jobStatusMap.values().stream()
.filter(value -> clazz.isAssignableFrom(value.getJobData().getClass()))
.map(value -> (JobStatus<T>) value)
.collect(Collectors.toList());
}
}

Why is this class not considered a supertype as a parameter?

Given the following example, why am I able to override the return type List<? extends IConfigUser> as List<ConfigUser> in getUserList() but cannot do the same for the parameter of setUserList()?
Isn't ConfigUser considered a supertype of IConfigUser in this case?
public class Test {
public interface IConfigUser {
}
public interface IConfig {
public List<? extends IConfigUser> getUserList();
public void setUserList(List<? extends IConfigUser> list);
}
public class ConfigUser implements IConfigUser {
}
// The type Test.Config must implement the inherited abstract method
// Test.IConfig.setUserList(List<? extends Test.IConfigUser>)
public class Config implements IConfig {
#Override
public List<ConfigUser> getUserList() {
return null;
}
// The method setUserList(List<ConfigUser> list) of type Test.Config
// must override or implement a supertype method
#Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
You can achieve your goal by adding a generic type parameter to IConfig:
public class Test {
public interface IConfigUser {
}
public interface IConfig<T extends IConfigUser> {
public List<T> getUserList();
public void setUserList(List<T> list);
}
public class ConfigUser implements IConfigUser {
}
public class Config implements IConfig<ConfigUser> {
#Override
public List<ConfigUser> getUserList() {
return null;
}
#Override
public void setUserList(List<ConfigUser> list)
{
}
}
}
You can return a more specific type in an override, but you can't require that you accept a more specific type. Get rid of the generics, and you can override a method returning Object with a method returning String, but you can't override a method accepting an Object parameter with a method accepting a String parameter.
All of this is so that callers are compatible. Consider:
IConfig config = new Config();
List<SomeOtherConfigUser> list = new ArrayList<SomeOtherConfigUser>();
list.add(new SomeOtherConfigUser());
config.setUserList(list);
Oops - your Config.setUserList is expecting every element to be a ConfigUser, not a SomeOtherConfigUser.
You can return ("specialize") the return type of getUserList() due to covariance, i.e. if you call that method on a IConfig reference all you know is that you'll get a List<? extends IConfigUser> and a List<ConfigUser> is a List<? extends IConfigUser> so the requirements are satisfied.
If you call that on a Config reference the information is more concrete but the basic requirements are still met.
With setUserList(...) the situation is different: it allows you to pass any "subclass" of List<? extends IConfigUser> which can be a List<ConfigUser> but it also can be something else, e.g. a List<SomeConfigUser>.
Btw, since you don't know the concrete generic parameter of list in setUserList(List<ConfigUser> list) the compiler will also only allow you to read from that list, never add to it - for the same reason as above: you don't know what you get and whether adding a ConfigUser is allowed because the list could only allow SomeConfigUser instances to be added.

Convert List<E> to List<T>, where T is abstract

I'm trying to generalize a method that I'll need to call a lot. It takes a List<E extends RealmObject> and return a List<T extends Pojo<E>>. The conversion from E to T is done via
new T().fromRealm(realmObject)
It won't work because T is an abstract class, so I can't instantiate it.
public static <E extends RealmObject, T extends Pojo<E>> List<T> fromRealmList(
RealmList<E> realmList) {
List<T> pojoObjects = new ArrayList<>();
if (realmList != null) {
for (E realmObject : realmList) {
try {
pojoObjects.add(new T().fromRealm(realmObject));
} catch (Exception e) {
e.printStackTrace();
}
}
}
return pojoObjects;
}
I also tried with this answer, but List<T> won't accept the object created with clazz.newInstance().
EDIT: adding Pojo class
public abstract class Pojo<R extends RealmObject> {
#NonNull
public abstract R toRealm();
#NonNull
public abstract Pojo<R> fromRealm(R realmObject);
}
EDIT2: adding an alternate solution, that still doesn't work: Required T, found Pojo<E>.
T newInstance = clazz.getConstructor()
.newInstance()
.fromRealm(realmObject);
pojoObjects.add(newInstance);
Apart from being an abstract class, T is also a parameter type, which cannot be used in a constructor new T().
A typical solution would be to use reflection:
pass an additional parameter Class<T> clazz to your method fromRealmList
invoke clazz.getConstructor(...).newInstance(...)
Maybe not perfect but that should work.
--edit-- The below is an example without using type T:
public static <E extends RealmObject> List<Pojo<E>> fromRealmList(
RealmList<E> realmList, Class<Pojo<E>> clazz) {
List<Pojo<E>> pojoObjects = new ArrayList<>();
...
Pojo<E> newInstance = clazz.getConstructor(...).newInstance(...).fromRealm(...);
pojoObjects.add(newInstance);
...
}

Basic Java type casting issue

I've an interface called DataHandler with the following declaration among others:
public List<Object> getIt();
while the ProjectSet class implements this interface.
This class handles Project objects and the implementation of the getIt() method for the ProjectSet class should return a list of Projects
like:
List<Project>
How to do this in Java?
Regards,
Gerard
You can take advantage of Generics in Java by declaring the method in your interface as:
public interface DataHandler<T> {
public List<T> getIt();
}
This means that the DataHandler interface is tied to a specific, unknown type T. The getIt() method returns a List of that class T. In other words, it could be seen as DataHandler will handle objects of class T.
And then provide your implementation, specifying that ProjectSet will be a DataHandler handling Project objects:
public class ProjectSet implements DataHandler<Project> {
public List<Project> getIt() { }
}
You might find this lesson of the Java Tutorials useful.
public List<T> getIt();
in your interface and
Like this
public interface MyInterface<T> {
public List<T> getIt();
}
then implement it with
implements MyInterface<Project>
You cannot do that in java this way.
My solution would be to have the data handler be generic
public interface DataHandler<T> {
public List<T> getIt();
}
then you can do
public ProjectSet implements DataHandler<Project> {
public List<Project> getIt() { ... }
}
You have 3 options:
Change the interface to be Generic:
interface DataHandler<T> {
List<T> getIt();
}
class ProjectSet implements DataHandle<Project> {
List<Project> getIt() {
...
}
}
This is hard because you need to change the interface, and refactorize all classes that implements DataHandler. This some thimes is not a option.
Cast a List
The type information of the list is gone in runtime, for this, all List type are equals in runtime, and equal to Object, so you can do this:
class ProjectSet implements DataHandle {
List<Object> getIt() {
...
return (List) projectList;
}
}
This is Ugly, but works!, you can add a #SuppressWarnings("unchecked") to skip the warnings.
Create a List of Objects
class ProjectSet implements DataHandle {
List<Object> getIt() {
List<Object> retObject = ... ;
for (Project p : getProjects()) {
retObject.add(p);
}
return retObject;
}
}
This is only ugly!.

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.

Categories

Resources