Casting to unbound generics in Java - 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());
}
}

Related

Using self-referential generic types in Java

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.

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.

Generic return types in java returns object

I have a method that is intended to allow consumers of my SDK to pull objects out of an internal store. These objects inherit from a base class that is a generic class. The true type of the object is deterministic and known only to the consumer. The setup looks like this:
public class MyBaseClass<T> {
...
}
public class TheBaseClassContainer {
private Map<String, MyBaseClass> container;
public <T extends MyBaseClass> T getOne(String id, Class<T> clazz) {
return clazz.cast(this.container.get(id));
}
}
The idea being that consumers can simply specify the class they're expecting back and we'll handle the rest. Unfortunately when I call this method like so:
TheBaseClassContainer container = ...;
MyBaseClassSubclass subclass = container.getOne("myId", MyBaseClassSubclass.class);
I get a compile failure saying that container.getOne is returning type MyBaseClass and the assignment is expecting an object of type MyBaseClassSubclass. Why is this happening?
Works for me mate:
class MyBaseClass<T> {
}
class B extends MyBaseClass<Integer>{}
class TheBaseClassContainer {
private Map<String, MyBaseClass> container;
public <T extends MyBaseClass> T getOne(String id, Class<T> clazz) {
return clazz.cast(this.container.get(id));
}
}
usage:
TheBaseClassContainer theBaseClassContainer = new TheBaseClassContainer();
B asd = theBaseClassContainer.getOne("asd", B.class);
Compiles in Java 7.

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);
}
}

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