what i'm trying to do is as follows:
assume that getClassFromString() and getAllObjectsFromRepositoryByClass() already exist.
why can't i use Class<T extends Named & HasId>.
i tried generifying the class itself, but can't use stuff like T.class etc.
public interface Named { String getDisplayName(); }
public interface HasId { String getId(); }
public class Foo {
public List<PairItem> getPairItems(String typeId) {
Class<T extends Named & HasId> clazz = getClassFromString(typeId);
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
List<PairItem> items = new ArrayList<>();
for (clazz obj : allObjects) {
items.add(obj.getDisplayName(),ibj.getId());
}
return items;
}
You can change you Foo-class in this way:
public class Foo {
public <T extends Named & HasId> List<PairItem> getPairItems(String typeId) {
Class<?> classFromString = getClassFromString(typeId);
// Java 8 seems to be unable to chain asSubclass-calls. These are merely to verify our unchecked cast
classFromString.asSubclass(Named.class);
classFromString.asSubclass(HasId.class);
//noinspection unchecked
return getPairItems((Class<T>) classFromString);
}
public <T extends Named & HasId> List<PairItem> getPairItems(final Class<T> clazz) {
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
List<PairItem> items = new ArrayList<>();
for (T obj : allObjects) {
items.add(new PairItem(obj.getDisplayName(), obj.getId()));
}
return items;
}
}
This fixes your problems with multiple boundaries as they are only allowed for type-parameters per documentation.; also I guess that
If one of the bounds is a class, it must be specified first.
leads to the problem that the asSubclass()-calls can not be chained, otherwise we could remove our unchecked cast.
The second method can profit from the streaming-API like this:
public <T extends Named & HasId> List<PairItem> getPairItems(final Class<T> clazz) {
List<T> allObjects = getAllObjectsFromRepositoryByClass(clazz);
return allObjects.stream()
.map(obj -> new PairItem(obj.getDisplayName(), obj.getId()))
.collect(Collectors.toList());
}
Overall I assumed that you wanted to instantiate PairItem and split the method so there is a unchecked and a fully-checked part.
Related
I am currently learning about the functionalities of the Optional class, and I am trying to build a simplified version of the Optional class. I was able to code ifPresent(), filter(), of(), map() and so on. However, I am currently stuck with the implementing or().
I know that or() have the signature Optional<T> or(Supplier<? extends Optional<? extends T>> supplier). However, my implementation assumed that I can access the contents of the Optional. As show below:
class Optional<T> {
private final T item;
...
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
if (this.item == null) {
T item = supplier.get().item;
return Maybe.<T>of(item);
} else {
return this;
}
}
}
As you can see, T item = supplier.get().item would throw an error saying that .item is inaccessible due to it being private. How am I able to access the item without causing this error?
First, you need to recall that you can not access a private field through an instance of a subtype, even though assigning the subtype reference to a variable of the current type, which allows the access, is possible without cast.
So if you have
public class ClassWithPrivateField {
private String field;
static class Subclass extends ClassWithPrivateField {}
void someMethod(Subclass obj) {
String s = obj.field; // does not work, you can't access field through Subclass
}
}
you may write
public class ClassWithPrivateField {
private String field;
static class Subclass extends ClassWithPrivateField {}
void someMethod(Subclass obj) {
ClassWithPrivateField withBroaderType = obj; // always works
String s = withBroaderType.field; // now, no problem to access field
}
}
Now to your more complicated generic variant. If you have
public class Optional<T> {
private final T item;
private Optional(T t) {
item = t;
}
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
if(this.item == null) {
T item = supplier.get().item;
return Optional.of(item);
}
else return this;
}
private static <T> Optional<T> of(T item2) {
return new Optional<>(item2);
}
}
the access to item is rejected by the compiler because the type returned by the supplier is ? extends Optional<? extends T> which is a subtype of Optional<? extends T>, just the same way as Subclass is a subtype of ClassWithPrivateField.
You can fix the issue the same way, by introducing a variable:
public class Optional<T> {
private final T item;
private Optional(T t) {
item = t;
}
Optional<T> or(Supplier<? extends Optional<? extends T>> supplier) {
if(this.item == null) {
Optional<? extends T> optional = supplier.get(); // valid assignment
T item = optional.item; // valid access
return Optional.of(item);
}
else return this;
}
private static <T> Optional<T> of(T item2) {
return new Optional<>(item2);
}
}
Alternatively, you could insert a type cast to Optional<? extends T> like
T item = ((Optional<? extends T>)supplier.get()).item;
but I would prefer the variant with a variable as it immediately shows to the reader that the assignment (without a cast) is a valid type transition which can never fail. The type cast can not fail either and is a no-op at runtime, but its syntax is indistinguishable from type casts performing a runtime check that could fail.
You just need to replace
T item = supplier.get().item;
return Maybe.<T>of(item);
with
return (Optional<T>)supplier.get();
I have a list of implementations to SomeInterface
List<SomeInterface> listOfThingsThatImplementsSomeInterface
I want to extract a specific implementation from the list according to its class name
private SomeInterface getThisType(SomeInterfaceImpl myType) {
SomeInterfaceImpl impl = null
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (current instanceof myType) {
impl = current
break;
}
}
return impl;
}
Is that possible in Java? should I be using generics?
First you need the Class instance of the desired class (which you have, you mention "according to its class name"). You can get a Class instance from the class name using
Class<?> cls = SomeInterfaceImpl.class;
or if you have the class name as a String:
Class<?> cls = Class.forName("package.ClassName")
or from an instance using
SomeInterfaceImpl myType = ...;
Class<?> cls = myType.getClass()
Then you can call this method, assuming your have a List<SomeInterface> listOfThingsThatImplementsSomeInterface somewhere:
private SomeInterface getThisType(Class<?> myType) {
for (SomeInterface current: listOfThingsThatImplementsSomeInterface) {
if (myType.isInstance(current)) {
return current;
}
}
return null; //nothing found
}
Suppose we have the desired implementation Class instance, (refer to #f1sh answer if the class is Class<?>), it can be done using Stream,
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
The key to match the type is using Class#isInstance.
Some points to note:
Make method return type generic so no cast is needed.
Class#cast can be used to convert the return type of the Stream.
Use Optional to handle case when no element matched.
Full example
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
public class FilterByClass {
List<SomeInterface> someInterfaceList = new ArrayList<>();
public static void main(String[] args) {
FilterByClass filterByClass = new FilterByClass();
filterByClass.someInterfaceList = List.of(new SomeInterfaceImplA(), new SomeInterfaceImplB(), new SomeInterfaceImplC());
System.out.println(filterByClass.getThisType(SomeInterfaceImplA.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplB.class).get().name());
System.out.println(filterByClass.getThisType(SomeInterfaceImplC.class).get().name());
}
private <T extends SomeInterface> Optional<T> getThisType(Class<T> type) {
return this.someInterfaceList.stream().filter(type::isInstance)
.map(type::cast).findFirst();
}
public interface SomeInterface {
default String name() {
return this.getClass().getSimpleName();
}
}
public static class SomeInterfaceImplA implements SomeInterface { }
public static class SomeInterfaceImplB implements SomeInterface { }
public static class SomeInterfaceImplC implements SomeInterface { }
}
The method should take the class as parameter. Let's say your interface is T, you can receive a parameter of type Class<? extends T>
Then go through the list and check for an element with the same class
Here is an example that should work:
private static <T> Optional<T> getThisType(
List<T> listOfThingsThatImplementsInterfaceT,
Class<? extends T> klass) {
return listOfThingsThatImplementsInterfaceT.stream()
.filter(klass::isInstance)
.findFirst();
}
Test with a list of Serializable
List<Serializable> listOfThingsThatImplementsSerializable = Arrays.asList(
new Integer(1), new Float(2), new Double(3)
);
System.out.println(
getThisType(listOfThingsThatImplementsSerializable, Float.class)
);
Looking for the Float returns Optional[2.0]
I Have a dozer mapping could convert class to class And I want to have general methode with type that I can just call it with Instance that I would
for example UserDto to User
User user = ConvertToUsingDozerMapping.convertToUsingDozerMapping(userDto)
for example AddressDto to Address
User user = ConvertToUsingDozerMapping.convertToUsingDozerMapping(addressDto)
public class ConvertToUsingDozerMapping<I,O> {
#Autowired
private DozerBeanMapperFactoryBean dozerBean;
public I convertToUsingDozerMapping(O o) {
Mapper mapper = null;
mapper = (Mapper) dozerBean.getObject();
I i= mapper.map(o, I.class);// doesn't compile
return i;
}
}
It work for me like that
public class ConvertToUsingDozerMapping {
#Autowired
private DozerBeanMapperFactoryBean dozerBean;
public I convertToUsingDozerMapping(O o, Class<? extends I> clazz) throws Exception {
Mapper mapper = null;
mapper = (Mapper) dozerBean.getObject();
I i= mapper.map(o, clazz);
return i;
}
}
when I want to use it I need to heritate the class
public class SignUpServiceImpl extends ConvertToUsingDozerMapping
But Like that I can do it just for User in all my class
I need to do use it for many object in the same class
Like that :
ConvertToUsingDozerMapping convertUserDtoToUser = new ConvertToUsingDozerMapping();
ConvertToUsingDozerMapping convertAddressDtoToAddress = new ConvertToUsingDozerMapping();
but when I do that it does not working I have exception nullpointerException att Mapper Idont know why ?
Do not use T.class inside the generic class/method. Instead extract the argument to the invoker that does not use generics adding a Class clazz argument.
About creating generic methods, use this scheme:
public <I, O> I convertToUsingDozerMapping(O o) {
...
}
EDIT:
Originally the question was answering more on how to make a generic method. I didn't focused on the mapper.map issue.
Indeed I saw the T.class and assumed directly that the question was issuing to convert with mapper.map into type I, that's why I added I.class, but as mentioned in the comments this does not work.
Now, focusing on the T.class issue:
I would solve it by getting out the T.class or I.class issue to outside the generic method and/or even outside the generic class if necesary by creating a new clazz argument, with the same type of mapper.map, from where you can use/specify manually which type to use (check the bottom example). After that you can pass directly the clazz argument to the mapper.map, without .class and without problems.
Check this if it works for you (a third T type can be used, or remove it and use only I and O):
public <I, O, T> I convertToUsingDozerMapping(O o, Class<? extends T> clazz) {
...
I i = mapper.map(o, clazz);
...
}
I add also a generic basic java compiler-test example. You can use it also as test-field for newer tests, it's simple but the map method arguments should be the same types as mapper.map:
class TestG {
public static <I, O, T> I map(O o, Class<? extends T> clazz) {
System.out.println("map dummy implementation");
return null; // this is only a check function, no implementation done
}
public <I, O, T> I convertToUsingDozerMapping(O o, Class<? extends T> clazz) {
I i = map(o, clazz);
return i;
}
public void testme() {
System.out.println("----- CONVERT TEST/ -----");
String s = "";
Integer i = 1;
String r = convertToUsingDozerMapping(i, String.class);
System.out.println("----- /CONVERT TEST -----");
}
public static void main(String[] args) {
TestG t = new TestG();
t.testme();
}
}
I am trying to do something like this:
1. Approach
Type ty = entityType.getEntityClass(); // could be e.g. String.class
List<ty> list;
2. Approach
Class cl = entityType.getEntityClass(); // could be e.g. String.class
List<cl> list;
However, compiler simply says "no".
Is there any way to set the generic type <T> of e.g. a java.util.List dynamic only by having e.g. String.class or foo.getClass()?
...
What I am actually trying to do is initializing a List by a given parameter of type EntityTypeEnum or it's Class property value.
public enum EntityTypeEnum {
ARTICLE(Article.class),
ORDER(OrderHeader.class),
CUSTOMER(Customer.class),
CUSTOMER_SESSION(CustomerSession.class);
private final Class entityClass;
private EntityTypeEnum(final Class entityClass) {
this.entityClass = entityClass;
}
public Class getEntityClass() {
return entityClass;
}
}
Constructive criticism is welcome.
Thank you!
Add: (as a response of Andy's comment)
Class cl = String.class;
List<cl> list;
..is not working either!
List<String> list;
..works, of course.
So what is this difference between String and String.class?
Or is there a way to set the value like:
public enum EntityTypeEnum {
ARTICLE(Article)
..
You are misunderstanding what Java generics are capable of: you can't do something based upon the value of a variable, only with the type of the variable.
Basically, Java generics are just an elision of casts: the compiler automatically inserts casts for you, and checks that the types resulting from those casts match up.
You can do what you describe in your example though, sort of, just not using enums. One of the shortcomings of enums in Java is that all elements have the same type.
Instead of using a real enum, you can use something that roughly looks like an enum:
final class EntityTypeEnumIsh {
private EntityTypeEnumIsh() {}
static final EntityClassSupplier<Article> ARTICLE =
new EntityClassSupplier<>(Article.class);
static final EntityClassSupplier<OrderHeader> ORDER =
new EntityClassSupplier<>(OrderHeader.class);
// ...
final class EntityClassSupplier<T> {
private final Class<T> clazz;
EntityClassSupplier(Class<T> clazz) { this.clazz = clazz; }
Class<T> getEntityClass() { return clazz; }
}
}
You can now use these in a method as you describe:
<T> List<T> method(EntityClassSupplier<T> supplier) {
return new ArrayList<>();
}
and invoke like this:
List<Article> list = method(EntityTypeEnumIsh.ARTICLE);
Of course, you don't get all of the niceness of a "real" enum (like serialization, resistance to reflection attacks etc). But you get something else useful, so weigh it up for your use case.
It does not work because Generics are a compile-time concept but you try to use it as a runtime concept.
The difference is that for compile-time concepts, the compiler needs to be able to figure out the type based on the information it has on your code (i.e., without running or evaluating it).
This code here would be syntactically correct:
public enum EntityTypeEnum
{
ARTICLE(String.class), // just using some builtin types to demonstrate
ORDER(Integer.class),
CUSTOMER(Double.class),
CUSTOMER_SESSION(Short.class);
private final Class<?> entityClass;
private EntityTypeEnum(final Class<?> entityClass)
{
this.entityClass = entityClass;
}
public Class<?> getEntityClass()
{
return this.entityClass;
}
}
class Test
{
// here, T is the type parameter which is determined from the class type
public <T> List<T> createList(final Class<T> clazz)
{
return new ArrayList<T>();
}
// this is the demo code on how to use it
public void foo()
{
EntityTypeEnum t = EntityTypeEnum.ARTICLE;
List<?> list = createList(t.getEntityClass());
}
}
The problem is that this does not help you much. List is more or less the same as List. The compiler cannot narrow the type down to a specific contained object class, because it depends on the runtime.
For your case, if you have a common superclass for your elements, you could use this information to narrow down the type:
public enum EntityTypeEnum
{
ARTICLE(Article.class),
ORDER(OrderHeader.class),
CUSTOMER(Customer.class),
CUSTOMER_SESSION(CustomerSession.class);
private final Class<? extends CommonParent> entityClass;
private EntityTypeEnum(final Class<? extends CommonParent> entityClass)
{
this.entityClass = entityClass;
}
public Class<? extends CommonParent> getEntityClass()
{
return this.entityClass;
}
}
class Test
{
public <T extends CommonParent> List<T> createList(final Class<T> clazz)
{
return new ArrayList<T>();
}
public void foo()
{
EntityTypeEnum t = EntityTypeEnum.ARTICLE;
List<? extends CommonParent> list = createList(t.getEntityClass());
}
}
But if you have a common parent, there is no benefit of the above code over just writing:
List<CommonParent> list = new ArrayList<CommonParent>();
and skipping all that additional generic stuff...
How do I write a method that takes a parameter of some type T which is an instance of Iterable, as well as a parameter of Class<E>, and return T<E>?
public static <...> ... checkedCast(T iterable, Class<E> clazz) {
// Check elements and throw ClassCastException if invalid
#SupressWarning("checked")
... cast = (...)iterable;
return cast;
}
I want to use it like this:
// This should compile
ArrayList<?> a = ...;
ArrayList<String> b = checkedCast(a, String.class);
// So should this
HashSet<Number> c = ...;
Set<Integer> d = checkedCast(c, Integer.class);
// This shouldn't compile
b = checkedCast(a, Integer.class);
// This shouldn't compile
b = checkedCast(c, Integer.class);
// This should throw ClassCastException
checkedCast(a, Integer.class);
I know I can do this using overrides, but this requires me to write an override for every type:
public static <T> Iterable<T> checkedCast(Iterable<?> iterable, Class<T> clazz) {...}
public static <T> List<T> checkedCast(List<?> list, Class<T> clazz) {...}
public static <T> ArrayList<T> checkedCast(ArrayList<?> list, Class<T> clazz) {...}
public static <T> Set<T> checkedCast(Set<?> set, Class<T> clazz) {...}
One of the weaknesses of the Java type system's Generics extension is that how we think about types in the singular doesn't scale to how we think of types in the plural.
In short, Collections of a generic type cannot be safely cast, ever. Build a new list, pull out each type and check it individually, and the return the new list. If you disregard this warning, I'll direct someone to do something like
List<Customer> customers = new ArrayList<>();
customers.add(new Customer(...));
List<Object> customerObjects = checkCast(customers, Object.class);
customerObjects.add(new Order(...));
You have been warned.
See if this works for you. But, people can help you better if you can describe in more detail why you need such a method.
public static
<InputElement, OutputElement extends InputElement,
InputContainer extends Iterable<InputElement>,
OutputContainer extends Iterable<OutputElement>>
OutputContainer checkedCast(InputContainer iterable,
Class<OutputElement> clazz) {
#SuppressWarnings("unchecked")
OutputContainer output = (OutputContainer) iterable;
return output;
}
This works/matches your requirements - except for throwing a ClassCastException (if you really want that behaviour, you can include it in the checkedCast method yourself):
import java.util.*;
public class CheckedCast {
public static <GenB, GenA extends GenB, CollA extends List<GenA>> List<GenB> checkedCast(CollA iterable, Class<GenB> clazz){
return (List<GenB>)iterable;
}
public static <GenB, GenA extends GenB, CollA extends Set<GenA>> Set<GenB> checkedCast(CollA iterable, Class<GenB> clazz){
return (Set<GenB>)iterable;
}
static class One {}
static class Two extends One {}
static class Three {}
public static void main(String[] args) {
ArrayList<Two> test1 = new ArrayList<Two>();
List<One> test2 = checkedCast(test1, One.class);
// Shouldn't compile...
ArrayList<One> aa = checkedCast(test2, One.class); // output is ArrayList
List<Two> bb = checkedCast(test2, Three.class); // Three is not superClass of Two
ArrayList cc = checkedCast(new HashSet(), Integer.class); // Set cannot become List
ArrayList<One> dd = checkedCast(new LinkedList<One>(), One.class); // ArrayList is not superClass of List
}
}
Updated to match new requirement: ArrayList xs = checkedCast(new HashSet(), Integer.class) - shouldn't compile
Update: updated to assert returned Collection generic type extends input Collection's generic type.