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!.
Related
Consider the following Java method:
<T extends List<T>> List<T> getMyList() {
return Collections.emptyList();
}
I can assign its output to a variable with a raw type, like so:
List x = getMyList();
List<List> y = getMyList();
But, I can't think of any way to assign its output to a fully parameterized type. In particular, I can't think of a non-raw, concrete type T that would satisfy List<T> z = getMyList();
Can we create such a T ?
If not, why not?
For context, I created this question while trying to understand how Enums are implemented in Java.
Here's an example of a concrete type that both works and starts to hint at a possible use-case (registration of some sort). The type consists acts like both an instance of some type, and as a container for all instances of that type.
public class WeirdEnum extends AbstractList<WeirdEnum> {
private static List<WeirdEnum> underlyingList = new ArrayList<>();
#Override
public WeirdEnum get(int index) { return underlyingList.get(index); }
#Override
public int size() { return underlyingList.size(); }
static <T extends List<T>> List<T> getAList() {
return Collections.emptyList();
}
public WeirdEnum() {
underlyingList.add(this); // Sufficient for our example but not a good idea due to concurrency concerns.
}
static List<WeirdEnum> foo = WeirdEnum.getAList();
}
Not sure if I fully understand your question, but here's an example:
class Example<T> implements List<Example<T>> {
...
}
...
List<Example<String>> list = getMyList();
Every enum in Java extends from the base-enum-class Enum<T extends Enum<T>>, where T is the actual type of the implementing enum.
When writing SomeClass<T extends SomeClass<T>> you can enforce that the type-parameter is always the implementing class itself.
Let's say you have this interface:
public interface MyInterface<T extends MyInterface<T>> {
T getSelf();
}
And this implementing class:
public class MyClass implements MyInterface<MyClass> {
public MyClass getSelf() {
return this;
}
}
In MyClass it is not possible to use any other type-parameter than MyClass itself.
Consider the abstract class:
public abstract class Animal { ...}
and the interface:
public interface Canine<T extends Animal> {...}
I've defined the concrete classes:
public class Dog extends Animal implements Canine<Dog> {...}
public class Wolf extends Animal implements Canine<Wolf> {...}
I'd like to build a repository class that accesses the database of animals and returns them. I've defined it in the following way:
public interface Repository {
Option<Dog> findById(String id, Class<Dog> type);
Option<Wolf> findById(String id, Class<Wolf> type);
(note: Option is taken from the vavr library)
This repository is used in the following class:
public abstract AbstractFinderClass<T extends Animal & Canine<T>> {
private Class<T> animalType;
public AbstractFinderClass(Class<T> animalType) {
this.animalType = animalType;
}
public Option<T> findMyAnimal(String id) {
return repository.findById(id, this.animalType);
}
}
which in turn is implemented in concrete form with:
public class DogFinder extends AbstractFinderClass<Dog> {
public DogFinder() {
super(Dog.class);
}
}
Now, the line return repository.findById(id, this.animalType) causes two errors:
on the second parameter, this.animalType is of type Class<T> while the expected type is Class<Dog>, and these are apparently incompatible;
the return type is expected to be Option<T> while instead I get Option<Dog>
I am afraid I am missing some "little" detail, as I would expect Dog and T to be compatible.
Could you help me in fixing the problem?
The first problem is that you're having an unnecessary type parameter for DogFinder. It's a dog finder, so a type parameter for what it finds is superfluous (the unconventionally named type parameter Dog could perhaps have indicated a problem). It should be:
class DogFinder extends AbstractFinderClass<Dog> {
public DogFinder() {
super(Dog.class);
}
}
Second, your Repository type has methods that are bound to specific types. This makes little sense because you want it to be generic. So you can use just one method, (optionally) making the repository itself generic (in the process solving the signature clash problem):
interface Repository<T extends Animal> {
Option<T> findById(String id, Class<T> type);
}
Third, unless we're missing context, I believe your Canine type doesn't need to be generic (unless things must be convoluted):
interface Canine {
}
If you need a dedicated canine finder, you can simply change your repository class, like so:
abstract class CanineFinderClass<T extends Animal & Canine>
implements Repository<T> {...}
As a side note, the DogFinder repository is redundant unless it offers special dog methods, like findAllPuppies(). Otherwise, making AbstractFinderClass concrete should be enough as the type is generic (just an example):
class AnimalFinderClass<T extends Animal> implements Repository<T> {
Repository<T> repository;
private Class<T> animalType;
public AbstractFinderClass(Class<T> animalType) {
this.animalType = animalType;
}
public Option<T> findMyAnimal(String id) {
return repository.findById(id, this.animalType);
}
}
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.
I am trying to convert a Collection of objects that implement DomainEntity to a Collection of objects that implement DomainEntityDTO. DomainEntity objects provide a method toDTO() to do the conversion.
Here is my code.
public class EntityCollectionConverter<T extends DomainEntityDTO, Y extends DomainEntity> {
public Collection<T> convert(Collection<Y> collection){
Collection<T> dtoList = new ArrayList<>();
for (DomainEntity domainObject : collection) {
DomainEntityDTO dto = domainObject.toDTO();
dtoList.add(dto); // Compiler: "T cannot be applied to DomainEntityDTO"
}
return dtoList;
}
}
The line dtoList.add(dto); doesn't compile, because "T cannot be applied to DomainEntityDTO'.
The interface DomainEntity looks like this:
public interface DomainEntity {
Long getId();
<T extends DomainEntityDTO> T toDTO();
}
Any idea where I am going wrong?
You need to declare your variable of type T.
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.