Generic specification in chained method call - java

public class Foo<T> {
public static <T> Foo<T> newFoo() {
return new Foo<>();
}
public Bar<T, T> toBar() {
return new Bar<>(this, new ArrayList<T>());
}
}
public class Bar<S, T> {
public Bar(Foo<T> Foo, List<S> list) {
}
public static void main(String[] args) {
Foo<Integer> newFoo = Foo.newFoo();
Bar<Integer, Integer> s = newFoo.toBar();
Bar<Integer, Integer> s2 = Foo.newFoo().toBar();
}
}
The first two lines of the main method work fine. The last line (Foo.newFoo().toBar()) gives me an error: Type mismatch: cannot convert from Bar<Object,Object> to Bar<Integer,Integer>. Is there a way to this in one line without getting an error? Casting to Bar<Integer, Integer> doesn't work.
More out of curiosity than necessity...

This works:
Bar<Integer, Integer> s2 = Foo.<Integer>newFoo().toBar();

Related

Java generic List name clash, has same erasure

I am writing a method with a generic List<T> as an argument. I want to limit T to Integer, Float and Double with this:
private Method(List<T> list) {
this.list = list;
}
public static <T extends Integer> Method<T> create(List<T> list) {
return new Method<>(list);
}
public static <T extends Float> Method<T> create(List<T> list) {
return new Method<>(list);
}
public static <T extends Double> Method<T> create(List<T> list) {
return new Method<>(list);
}
But I get this error:
error: name clash: <T#1>create(List<T#1>) and <T#2>create(List<T#2>) have the same erasure
public static <T extends Float> Method<T> create(List<T> list) {
^
where T#1,T#2 are type-variables:
T#1 extends Float declared in method <T#1>create(List<T#1>)
T#2 extends Integer declared in method <T#2>create(List<T#2>)
I get the same error for T#1 extends Double as well.
The code is based on this answer, which works well. So I think the problem is related to the fact that I used a list of generics as an input instead of a single generic.
How can I fix this? Is there some way to give Java the ability to discern between the different instances?
You could use the Number superclass of Integer, Float, and Double as your bound.
public class Method<T extends Number> {
private final List<T> list;
public Method(List<T> list) {
this.list = list;
}
public static void main(String[] args) {
var mFloats = new Method(Arrays.asList(1.0f, 2.0f, 3.0f));
var mDoubles = new Method(Arrays.asList(1.0,2.0,3.0));
var mInts = new Method(Arrays.asList(1,2,3));
}
}
Type Erasure affects Generic Collections like List, so each generic method is type erased into having a parameter signature with parameter type Obejct. See Oracle Docs To avoid this you can use arrays instead.
import java.util.Arrays;
import java.util.List;
public class Method<T> {
private final List<T> list;
private Method(List<T> list) {
this.list = list;
}
public static <T extends Integer> Method<T> create(T[] arr) {
return new Method<>(Arrays.asList(arr));
}
public static <T extends Float> Method<T> create(T[] arr) {
return new Method<>(Arrays.asList(arr));
}
public static <T extends Double> Method<T> create(T[] arr) {
return new Method<>(Arrays.asList(arr));
}
public static void main(String[] args) {
var floatMethod = Method.create(new Float[] {1.0f, 2.0f});
var doubleMethod = Method.create(new Double[] {1.0, 2.0});
var intMethod = Method.create(new Integer[] {1, 2});
}
}

Exception java.lang.IllegalArgumentException: is not an interface when using dynamic proxies

I want to implement a generic functionality which would enable that our domain classes are being proxied for the case that its values to be xml compliant (escaping special characters in strings). The domain classes/objects are being generated, so that they can not be changed by me. What I tried to do was following code for the generation of proxies:
public class StringValuesFormatterForXml implements InvocationHandler {
public static interface IA {
String getMa1();
List<? extends IB> getBs();
}
public static class A implements IA {
#Override
public String getMa1() {
return "Ma1";
}
#Override
public List<? extends IB> getBs() {
return Arrays.asList(new B(), new B());
}
}
public static interface IB {
String getMb1();
String getMb2();
}
public static class B implements IB {
#Override
public String getMb1() {
return "Mb1";
}
#Override
public String getMb2() {
return "Mb2";
}
}
Object destObj;
private final Map<String, Method> methods = new HashMap<>();
#SuppressWarnings("unchecked")
public static IA createProxyA(IA destObj) {
return (IA) Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] {
IA.class
}, new StringValuesFormatterForXml(destObj));
}
#SuppressWarnings("unchecked")
public static Object createProxy(Object destObj, Class<?> clazz) {
return Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] {
clazz
}, new StringValuesFormatterForXml(destObj));
}
public StringValuesFormatterForXml(Object destObj) {
this.destObj = destObj;
for (Method method : destObj.getClass().getMethods()) {
this.methods.put(method.getName(), method);
}
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.getReturnType().isAssignableFrom(List.class)) {
List<Object> elems = (List<Object>) method.invoke(destObj, args);
List<Object> proxyElems = new ArrayList<Object>();
for (Object obj : elems) {
Object proxyObj = createProxy(obj, obj.getClass());
proxyElems.add(proxyObj);
}
return proxyElems;
}
return method.invoke(destObj, args); // Here I will format the output for xml
}
public static void main(String[] args) {
A orig = new A();
IA proxy1 = createProxyA(orig);
A proxy2 = (A) createProxy(orig, orig.getClass());
}
}
Code in createProxy(orig, orig.getClass()) throws following error java.lang.IllegalArgumentException: StringValuesFormatterForXml$A is not an interface but the code createProxyA(orig) does not. So it seems that I would need to have a separate creator method for every interface which I use. In our domain model there are many classes and I do not want to create for every class separate creator.
Are there any other ways/frameworks which are better suited for my case of proxying objects.
Your createProxy method does work, you just have to pass the class of the interface as second parameter:
A orig = new A();
IA proxy1 = (IA) createProxy(orig, IA.class);
In addition I would recomment you to use the createProxy function as a generic function in order to avoid the obkect cast:
#SuppressWarnings("unchecked")
public static <T> T createProxyB(T destObj, Class<T> clazz) {
return (T) Proxy.newProxyInstance(destObj.getClass().getClassLoader(), new Class[] { clazz },
new StringValuesFormatterForXml(destObj));
}
In this case you can call the function like this:
A orig = new A();
IA proxy1 = createProxyB(orig, IA.class);

How to use Function<X, Y> as Function<Object, Object> in Java?

(Java newbie here)
I try to implement chain of functions in Java where the input/return types are unknown. They will work so that the output of F(n) will feed F(n+1) and so on. First I need to implement MyFunction<?, ?> class but here starts the problem.
What I tried (simplified)
public class MyFunction implements Function<Object, MyList<? extends Object>> {
private final Function<Object, MyList<? extends Object>> method;
public MyFunction(Function<Object, MyList<? extends Object>> method) {
this.method = method;
}
public MyList<? extends Object> apply(Object input) {
return method.apply(input);
}
public static MyList<String> myMethod(MyClass myClass) {
return new MyList<String>();
}
public static void main(String[] args) {
MyFunction myFunction = new MyFunction(input -> myMethod(input));
// ^^^^^^^^
// |
// +---------------------------------------------+
// |
// v
// The method myMethod(MyClass) in the type MyFunction is not
// applicable for the arguments (Object)
}
}
As far as I know, everything is an Object in java. But here the error says different.
The method myMethod(MyClass) in the type MyFunction is not applicable for the arguments (Object)
Then I tried (ignoring type-safety)
public class MyFunction implements Function {
private final Function method;
public MyFunction(Function method) {
this.method = method;
}
public Object apply(Object input) {
return method.apply(input);
}
public static MyList<String> myMethod(MyClass myClass) {
return new MyList<String>();
}
public static void main(String[] args) {
MyFunction myFunction = new MyFunction(input -> myMethod(input));
}
}
And the error is still the same since apply expects object. Because
The type MyFunction must implement the inherited abstract method Function.apply(Object)
Also tried
public class MyFunction implements Function<? super Object, MyList<? extends Object>>
This time the error is:
A supertype may not specify any wildcard
Even when it works, I don't know how to use it in the way below.
public Object apply(? super Object input)
My questions
What might be the problem? How can I pass my Function<X, Y> into it?

How to initializing Class<T> at interface default method?

I have an interface:
public interface ITransformer<S,T>{
public void transform(S source,T target);
default String getTransformerName(){
Class<S> s;
Class<T> t;
return s.getName() + t.getName(); //*********
}
}
the error message the starred line:
The local variable s may not have been initialized
The local variable t may not have been initialized
I would like to use this method to return a string with [S.classname][T.classname] . Please let me know how to achieve this or is this impossible to do at interface ?
Update: Jan 12
My purpose of doing this is due to the fact that this class will be in framework and I want to reduce the human error as much as possible.. I am changing the code as follows:
public interface ITransformer<S,T>{
public void transform(S source,T target);
public FieldEntry<S, T> getTransformerName();
}
public class FieldEntry<S,T> implements Comparable<FieldEntry> {
private Class<S> s;
private Class<T> t;
public FieldEntry(Class<S> s,Class<T> t){
this.s = s;
this.t = t;
}
public String getEntryName(){
return s.getName() + t.getName();
}
#Override
public int compareTo(FieldEntry entry) {
if(entry == null) throw new IllegalArgumentException("The argument to compare cannot be null!");
return entry.getEntryName().compareTo(this.getEntryName());
}
}
In order to demonstrate why this can’t work, you may change your class to
public interface ITransformer<S,T>{
public void transform(S source,T target);
static <In,Out> ITransformer<In,Out> noOp() {
return (source,target) -> {};
}
static void main(String... arg) {
ITransformer<String,Integer> t1 = noOp();
ITransformer<Long,Thread> t2 = noOp();
System.out.println(t1 == (Object)t2);
}
}
Running this will print true. In other words, both functions are represented by the same instances, so there can’t be and property allowing to recognize their different type.
Generally, when two functions (lambda expressions or method references) exhibit the same behavior, a JVM may represent them by the same implementation type or even the same instance.
Even for non-interface classes, this doesn’t work due to Type Erasure. It only works when you have a reifiable (i.e. non-generic) type extending or implementing a generic type.
It's a little bit dangerous and I wouldn't used this in production (because you should cover in your code all possible use cases of your interface), but you can use reflection for it:
public interface ITransformer<S, T> {
public void transform(S source, T target);
default String getTransformerName() {
Type[] genericInterfaces = this.getClass().getGenericInterfaces();
ParameterizedType parameterizedType = null;
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
ParameterizedType paramInterface = (ParameterizedType) genericInterface;
if (paramInterface.getRawType().equals(ITransformer.class)) {
parameterizedType = paramInterface;
break;
}
}
}
if (parameterizedType == null) {
throw new IllegalStateException("!");
}
return parameterizedType.getActualTypeArguments()[0].getTypeName() + parameterizedType.getActualTypeArguments()[1].getTypeName();
}
}
public class StringToIntegerTransfomer implements ITransformer<String, Integer> {
#Override
public void transform(String source, Integer target) {
}
}
public interface StringToNumberTransfomer<T extends Number> extends ITransformer<String, T> {
}
public class StringToLongTransfomer implements StringToNumberTransfomer<Long>, ITransformer<String, Long> {
#Override
public void transform(String source, Long target) {
}
}
#Test
public void test() {
ITransformer<String, Integer> intTransformer = new StringToIntegerTransfomer();
ITransformer<String, Long> longTransformer = new StringToLongTransfomer();
ITransformer<String, String> stringTransformer = new ITransformer<String, String>() {
#Override
public void transform(String source, String target) {
}
};
ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>() {
#Override
public void transform(String source, Double target) {
}
};
System.out.println(String.format("intTransformer: %s", intTransformer.getTransformerName()));
System.out.println(String.format("longTransformer: %s", longTransformer.getTransformerName()));
System.out.println(String.format("stringTransformer: %s", stringTransformer.getTransformerName()));
System.out.println(String.format("doubleTransformer: %s", doubleTransformer.getTransformerName()));
}
Output for this snippet:
intTransformer: java.lang.Stringjava.lang.Integer
longTransformer: java.lang.Stringjava.lang.Long
stringTransformer: java.lang.Stringjava.lang.String
java.lang.IllegalStateException: !
This code has one restriction, you should say implements ITransformer<S, T> for all implementations of ITransformer. That why I have got IllegalStateException for this line ITransformer<String, Double> doubleTransformer = new StringToNumberTransfomer<Double>(). But you can improve this code.
Better option is to use some base implementation of interface and pass source and target classes into constructor:
public interface ITransformer<S, T> {
void transform(S source, T target);
String getTransformerName();
}
public abstract class BaseITransformer<S, T> implements ITransformer<S, T> {
private final Class<S> sourceClass;
private final Class<T> targetClass;
public BaseITransformer(Class<S> sourceClass, Class<T> targetClass) {
this.sourceClass = sourceClass;
this.targetClass = targetClass;
}
public String getTransformerName() {
return sourceClass.getName() + targetClass.getName();
}
}
In Java it is impossible to get a Class<S>, unless you already know which class S is, or something else that knows which class S is gives you one.

Need some slight help on this generic Java

I'm trying to make this code as generic as possible, but im stuck right on the last part. This is where my code is called:
List<Integer> NewList = map(OriginalList, new IFunction<Integer>(){
public <T extends Number> int execute(T anInt){
return anInt.intValue() + 1;
}
});
then I have the method map:
public static <T> List<Integer> map(List<T> c, IFunction<T> f) {
List<Integer> TempList = new ArrayList<Integer>();
for (T o : c){
TempList.add(f.execute(o));
}
return TempList;
}
and the interface IFunction:
public interface IFunction<T> {
public <T extends Number> int execute(T o);
}
my error is in Map() where it says TempList.add(f.execute(o)); i am trying to declare the TempList to be of type T and the execute method to return an incremented number in Type T.
Every time i fix one part of the code i seem to have ruined another part. Ideally all parameters would be generic and there would be no 'Integer' anywhere except where i call my code
You need to constrain your parameter in the map() method:
public static <T extends Number> List<Integer> map(List<T> c, IFunction<T> f) {
...
Otherwise f.execute() will complain that the type of the argument can be anything, and it expects a Number.
Try this:
IFunction.java
public interface IFunction <T extends Number> {
T execute(T obj);
}
Main.java
public class Main {
public static void main(String[] args) {
List<Integer> originalList = new ArrayList<Integer>();
List<Integer> newList = map(originalList, new IFunction<Integer>(){
public Integer execute(Integer anInt){
return anInt.intValue() + 1;
}
});
}
public static <T extends Number> List<T> map(List<T> c, IFunction<T> f) {
List<T> tempList = new ArrayList<T>();
for (T o : c){
tempList.add(f.execute(o));
}
return tempList;
}
}
You should try a different Generic Setup:
public interface IFunction<T extends Number> {
public int execute(T o);
}
List<Integer> NewList = map(OriginalList, new IFunction<Integer>(){
public int execute(Integer anInt){
return anInt.intValue() + 1;
}
});
public static <T extends Number> List<Integer> map(List<? extends T> c, IFunction<T> f) {
List<Integer> tempList = new ArrayList<Integer>();
for (T o : c){
tempList.add(f.execute(o));
}
return tempList;
}
This is as close as I could get to removing Integer (changing variable names to start lower case):
public class Main
{
public static void main(String[] args)
{
List<Integer> originalList = new ArrayList<Integer>();
originalList.add(1);
originalList.add(2);
originalList.add(3);
originalList.add(4);
List<Integer> newList = map(originalList, new IFunction<Integer>()
{
public <T extends Number> T execute(T aNumber)
{
Integer result = aNumber.intValue() + 1;
return (T) result;
}
});
System.out.println(newList);
}
public static <T extends Number> List<T> map(List<T> c, IFunction<T> f)
{
List<T> tempList = new ArrayList<T>();
for (T number : c)
{
tempList.add(f.execute(number));
}
return tempList;
}
}
and
public interface IFunction<T> {
public <T extends Number> T execute(T o);
}
Still got one inside the implementation of execute().

Categories