This works nicely:
// Return all objects with code 'code'.
static List<? extends ICode> getObjects(String code, List<? extends ICode> list)
{
<ICode> retValue = new ArrayList<ICode>();
for (ICode item : list)
{
if (item.getCode().equals(code))
{
retValue.add(item);
}
}
return retValue;
}
The 'singular' version can be:
// Return the first object found with code 'code'.
static ICode getObject(String code, List<? extends ICode> lijst)
{
for (ICode item : lijst)
{
if (item.getCode().equals(code)) return item;
}
return null;
}
But instead of return value ICode I would like return value <? extends ICode>.
Can it be done?
See Jon Skeets answer, I now prefer to use the T instead of ? also in the plural version:
// Return all objects with code 'code'.
public static <T extends ICode> List<T> getObjects(String code, List<T> lijst)
{
List<T> retValue = new ArrayList<T>();
for (T item : lijst)
{
if (item.getCode().equals(code))
{
retValue.add(item);
}
}
return retValue;
}
I assume you want it to be the same type as the actual list. In that case, this should do it:
static <T extends ICode> T getObject(String code, List<T> list)
{
for (T item : list)
{
if (item.getCode().equals(code)) return item;
}
return null;
}
If you let the return type be ICode then you can return any type that extends ICode.
Related
I have command interface
public interface ICommand {...}
and handler interface that is associated with specific command
public interface ICommandHandler<T extends ICommand> {
IResponse handle(T command);
}
For example, I have concrete command
public class GetCatalogById implements ICommand{
private final long catalogId;
public GetCatalogById(long catalogId) {
this.catalogId = catalogId;
}
public long getCatalogId() {
return catalogId;
}
}
How programmatically get list (List) of all classes in project that
implements ICommandHandler<GetCatalogById>
?
Your problem can be divided into 2 subproblems:
Getting a list of all classes that implement ICommandHandler
Filtering ones which have a required type parameter
As #ArvindKumarAvinash said, you can find many solutions to the first subproblem here.
And here is my solution for a second one:
public static <T extends ICommand> List<Class<? extends ICommandHandler<T>>> getCommandHandlers(
Class<T> commandClass, String packageName
) {
return new Reflections(packageName).getSubTypesOf(ICommandHandler.class).stream()
.filter(subtype -> !subtype.isInterface())
.filter(subtype -> Objects.equals(getParameter(subtype, ICommandHandler.class, 0), commandClass))
.map(subtype -> (Class<? extends ICommandHandler<T>>) subtype)
.collect(Collectors.toList());
}
#Nullable
public static <T> Type getParameter(
Class<T> clazz,
Class<? super T> parametrizedParent,
int index
) {
Type result = null;
for (ParameterizedType parent : getParameterizedParents(clazz, parametrizedParent)) {
result = parent.getActualTypeArguments()[index];
if (!(result instanceof TypeVariable)) return result;
index = getTypeVariableIndex((TypeVariable<?>) result);
}
return result;
}
private static <T> List<ParameterizedType> getParameterizedParents(Class<? extends T> clazz, Class<T> parent) {
List<ParameterizedType> genericParents = new ArrayList<>();
Class<? extends T> current = clazz;
while (true) {
Type supertype = getSuperType(current, parent);
if (supertype instanceof ParameterizedType)
genericParents.add((ParameterizedType) supertype);
else genericParents.clear();
Type rawSupertype = toRawType(supertype);
if (rawSupertype == parent) {
Collections.reverse(genericParents);
return genericParents;
}
current = (Class<? extends T>) rawSupertype;
}
}
private static <T> Type getSuperType(Class<? extends T> child, Class<T> parent) {
if (child == parent) return child;
Type superclass = child.getGenericSuperclass();
if (isSubTypeOfClass(superclass, parent)) return superclass;
for (Type type : child.getGenericInterfaces())
if (isSubTypeOfClass(type, parent)) return type;
throw new IllegalArgumentException(child.getName() + " is not assignable from " + parent.getName());
}
private static int getTypeVariableIndex(final TypeVariable<?> typeVariable) {
return Arrays.asList(typeVariable.getGenericDeclaration().getTypeParameters()).indexOf(typeVariable);
}
private static boolean isSubTypeOfClass(Type type, Class<?> clazz) {
Type rawType = toRawType(type);
return rawType instanceof Class && clazz.isAssignableFrom((Class<?>) rawType);
}
private static Type toRawType(Type type) {
return type instanceof ParameterizedType ? ((ParameterizedType) type).getRawType() : type;
}
Best way to avoid this warning? Is there any case/example where the (T) cast can fail? (Java language compiled with Eclipse)
Example updated for reference with Lee's answer: cast fail subtly using result.
interface Test {
}
class Test1 implements Test {
void doSomething() {}
}
class Test2 implements Test {}
public class TestIterable<T extends Test> implements Iterable<T> {
final ArrayList<T> result=new ArrayList<>();
public TestIterable(Object obj) {
if (obj instanceof Test) {
Test t = (Test) obj;
result.add((T) obj); // Warning: unchecked cast from Test to T
// Iteresting decompilation result....
// result.add((Test) obj);
}
}
#Override
public Iterator<T> iterator() {
return result.iterator();
}
public static void main(String[] args) {
TestIterable<Test1> x = new TestIterable<>(new Test2());
for (Test1 y :x.result) {
y.doSomething();
// java.lang.ClassCastException
};
}
}
Two alternatives. The natural solution to require a T object probably does not fit your needs. Then the type T has to be explicitly passed because of the type erasure making any other construct senseless.
class TestIterable<T extends Test> implements Iterable<T> {
final List<T> result = new ArrayList<>();
public TestIterable(T obj) {
result.add(obj);
}
public TestIterable(Class<T> type, Object obj) {
if (obj == null || type.isAssignableFrom(obj.getClass())) {
result.add(type.cast(obj));
}
}
#Override
public Iterator<T> iterator() {
return result.iterator();
}
}
I have a little piece of code where i created my own java.util.stream realization.
I need to parametrize it using PECS rule. But either I didn't understand PECS rule well or my class designed bad - I don't know how to correctly implement it.
When I'm trying to implement it (? extends T) in filter() method realization, for example - I can't use foreach cycle.
Maybe you have some ideas? Thanks in advance.
public class Streams<T> {
private final List<T> list;
private List<T> resultList = new ArrayList<>();
private Streams(List<T> list) {
this.list = list;
}
public static <E> Streams<E> of(List<E> list) {
return new Streams<>(list);
}
public Streams<T> filter(Predicate<T> predicate) {
for (T elem : list) {
if (predicate.test(elem)) {
resultList.add(elem);
}
}
return this;
}
public Streams<T> transform(Function<? super T, ? extends T> function) {
for (T elem : resultList) {
resultList.set(resultList.indexOf(elem), function.apply(elem));
}
return this;
}
public <E, I> Map<E, I> toMap(Function<T, E> function1, Function<T, I> function2) {
HashMap<E, I> map = new HashMap<>();
for (T elem : resultList) {
map.put(function1.apply(elem), function2.apply(elem));
}
return map;
}
}
I have this code:
public class Test<T extends Number>{
public static void main(String[] args){
Test<Short> test = new Test(Short.class);
System.out.println(test.get());
}
private Class<T> clazz;
public Test(Class<T> clazz){
this.clazz=clazz;
}
public T get(){
if(clazz == Short.class)
return new Short(13); //type missmatch cannot convert from Short to T
else return null;
}
}
but it does not compile... Any Idea how I repair this?
You cannot construct a Short with an int (there is no such constructor), and you could cast to T like
public T get() {
if (clazz == Short.class)
return (T) Short.valueOf((short) 13);
else
return null;
}
Because your return type is generic T not Short. so you will get type mismatch.
The kind of construction in your code looks more suitable for a non-generics implementation:
Instead of:
public T get() {
Declare it as:
public Number get () {
Even if you write below, compiler will complain
Short s = new Short(13); //The constructor Short(int) is undefined
workaround
Short s = new Short((short) 13);
your case
return (T) new Short((short) 13);
public T get() {
if (clazz == Short.class) {
Short s = 13;
return (T) s;
} else {
return null;
}
}
If I have this class:
class Foo<T> implements SomeInterface
{
final private List<T> list = new ArrayList<T>();
final private Class<? extends T> runtimeClass;
public Foo(Class<? extends T> cl) { this.runtimeClass = cl; }
// method override from SomeInterface
#Override public boolean addChild(Object o)
{
// Only add to list if the object is an acceptible type.
if (this.runtimeClass.isInstance(o))
{
list.add( /* ??? how do we cast o to type T??? */ );
}
}
public List<T> getList()
{
return this.list;
} // yes, I know, this isn't safe publishing....
}
how would I perform a runtime cast from Object to type T?
Use this:
list.add(this.runtimeClass.cast(o))
See Class.cast() for details
// method override from SomeInterface
#Override public boolean addChild(Object o)
{
// Only add to list if the object is an acceptible type.
if (this.runtimeClass.isInstance(o))
{
list.add((T)o);
}
}