I am currently automating a process of a data handler. What I mean with automating is that the DataHandlers are initiated automatically via reflection based on a specific configuration.
But I am on a point where I do not know how I should solve this problem. It is about this peace of code:
Class<?> clazz = classLoader.loadClass(d);
Object values = clazz.getMethod("values").invoke(null);
RSA.addDataHandler(clazz,new DataHandlerSetAdapter<>(values));
I am loading the class via the classLoader and invoking a static method called "values" which returned a bunch of, you have suggested right, values!
Now the problem is with new DataHandlerSetAdapter<>(values)) which has an error in <> because the Object does not know which class to initiate.
Cannot infer arguments (unable to resolve constructor)
Would this code be in C# I would use typeof() but in JAVA there is nothing like this maybe instanceof but I cannot use this at this point. Btw .values() is returning an Array of the same type class (enum).
How can I solve this problem?
//edit
with the method .getReturnType() on the Method I would get the return type but I cannot apply it to the DataHandlerSetAdapter<>
Class DataHandlerSetAdapter
public class DataHandlerSetAdapter<T> implements DataHandler<T> {
private final Set<T> values = new ConcurrentSkipListSet<>();
.
.
.
}
It is not clear to me what you are trying to do. But if the loadable class is an enum, then why you are not doing it like this:
Class<? extends Enum<?>> clazz = classLoader.loadClass(d);
Enum<?>[] values = clazz.getEnumConstants();
RSA.addDataHandler(clazz, new DataHandlerSetAdapter<>(values));
Alternatively you can use raw types:
RSA.addDataHandler(clazz, new DataHandlerSetAdapter(values)) - note no diamonds <>.
But Still I'm not sure weather will this work for you or not. Please provide the following information to understand the root cause of failure.
Signature of DataHandlerSetAdapter constructor
Signature of RSA.addDataHandler(...) method
More info about RSA you used in your code snippet. (e.g. Is it a class or object)
Related
Consider the following two lines of code:
final List<Path> paths = new ArrayList<>();
final FileVisitor<Path> fv = new SimpleFileVisitor<>();
To me, they look quite similar. However, the second line is refused by the Java compiler (1.8) with the message "Cannot infer type arguments for SimpleFileVisitor<>".
Can anyone please explain, what's the problem?
I don't see how you may get the error message Cannot infer type arguments because your syntax is correct, except for the fact that as many have said already, the class java.nio.file.SimpleFileVisitor has only one constructor which is protected:
protected SimpleFileVisitor() {
}
This means that only children of this class can initialize an instance of SimpleFileVisitor, and that's why your code doesn't compile.
I don't know this class, but by a quick look at the code I guess they simply expect you to extend it first (or use an already existing extension coming from somewhere else), and then use it the implementations of the FileVisitor interface.
If you don't have a concrete child class to use and want to create your own MySimpleFileVisitor:
public class MySimpleFileVisitor<T> extends SimpleFileVisitor<T> {
public MySimpleFileVisitor() {
super(); //<-- here you have the right to call the protected constructor of SimpleFileVisitor
}
}
... you will then be able to instantiate your class and use the already implemented methods like this:
FileVisitor<Path> fv = new MySimpleFileVisitor<>(); //<-- here you will be able to correctly infer parameter type as you do in your List example
fv.visitFile(file, attrs); //<-- here you enter the method implemented inside SimpleFileVisitor
This is the method:
protected <T> TestPageResult<T> getTestPageResutForRequest(MockHttpServletRequestBuilder request) throws Exception {
String responseJson = mockMvc.perform(request).andReturn().getResponse()
.getContentAsString();
TestPageResult<T> response = getObjectMapper().readValue(responseJson,
new TypeReference<TestPageResult<T>>() {
});
return response;
}
I call it like this:
TestPageResult<SomeDto> pageResult = this.<SomeDto>getTestPageResutForRequest(getRequest());
TestPageResult is:
protected static class TestPageResult<T> {
private List<T> items;
private long totalCount = -1;
public TestPageResult() {
}
//omitted getters and setters
}
The resulting pageResult.getItems() contains a List of LinkedHashMap instead of a list of SomeDto. If I were to just hardcode the SomeDto type in the objectMapper.readValue method I'd get the correct results.
What's the problem?
edit: The suggested duplicated did solve my problem - kind of.
I used:
JavaType type = getObjectMapper().getTypeFactory().constructParametricType(TestPageResult.class, clazz);
TestPageResult<T> response = getObjectMapper().readValue(responseJson, type);
Problem is there is no going around not passing down a Class argument to the method. So the method looks ugly due to both passing a generic type and the same thing as a Class. Obviously you can just not pass the generic now but this way a casting would be required and adding SuppressWarnings and so on.
The problem is erasure. All these <T> parameters don't exist in the compiled code, after they're erased. This means that source new TypeReference<TestPageResult<T>>() looks like new TypeReference<TestPageResult>() once compiled, which is not what you want. (Similar to how a List<String> ends up being a List in compiled code, and it's just compile-time validation that you don't add Integers to your String List.)
I think there's roughly two ways to deal with this (in this case), both of these you already stumbled upon:
Either you create a type that properly represents what you want, such as: new TypeReference<TestPageResult<SomeDto>>(), or class SomeDtoPageResult extends TestPageResult<SomeDto> which you can then use in places like readValue(..., SomeDtoPageResult.class);
Or you create a complete class representation, like you were doing with JavaType
What you really want won't work. Your best bet is to tinker and come up with the cleanest code that solves it. Generics let you express really elaborate structures, and when you serialize an actual instance (nested objects), that comes out just fine, but when the classes need to be introspected at runtime, e.g. for deserialization (your use case) or to build a model (e.g. to generate Swagger docs), this becomes problematic.
I have a cache that compartmentalizes by namespace. I would like to use class type to determine which cache to use. The following method gives an idea of what I want to accomplish. I use the word cache loosely. I am more interested in correcting my design pattern so it works.
public static DObject getFromCache(String key,Class<T extends DObject> type) {
MyCache cache = getWithName(type.getName());
// ......
type.class value = (type.class) cache.get(key);
// ......
}
where DObject is a naming interface. How do I fix so that type.class value = (type.class) cache.get(key) works well? I know this would be a joke for Scala but I want to use Java.
T value = type.cast(cache.get(key));
(You can declare variables of type T just fine, but type erasure means you can't cast to T. Luckily Class#cast is there to help.)
I have some legacy Java code that defines a generic payload variable somewhere outside of my control (i.e. I can not change its type):
// Java code
Wrapper<? extends SomeBaseType> payload = ...
I receive such a payload value as a method parameter in my code and want to pass it on to a Scala case class (to use as message with an actor system), but do not get the definitions right such that I do not get at least a compiler warning.
// still Java code
ScalaMessage msg = new ScalaMessage(payload);
This gives a compiler warning "Type safety: contructor... belongs to raw type..."
The Scala case class is defined as:
// Scala code
case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T])
How can I define the case class such that the code compiles cleanly? (sadly, changing the code of the Java Wrapper class or the type of the payload parameter is not an option)
Updated to clarify the origin of the payload parameter
Added For comparison, in Java I can define a parameter just in the same way as the payload variable is defined:
// Java code
void doSomethingWith(Wrapper<? extends SomeBaseType> payload) {}
and call it accordingly
// Java code
doSomethingWith(payload)
But I can't instantiate e.g. a Wrapper object directly without getting a "raw type" warning. Here, I need to use a static helper method:
static <T> Wrapper<T> of(T value) {
return new Wrapper<T>(value);
}
and use this static helper to instantiate a Wrapper object:
// Java code
MyDerivedType value = ... // constructed elsewhere, actual type is not known!
Wrapper<? extends SomeBaseType> payload = Wrapper.of(value);
Solution
I can add a similar helper method to a Scala companion object:
// Scala code
object ScalaMessageHelper {
def apply[T <: SomeBaseType](payload: Wrapper[T]) =
new ScalaMessage(payload)
}
object ScalaMessageHelper2 {
def apply[T <: SomeBaseType](payload: Wrapper[T]) =
ScalaMessage(payload) // uses implicit apply() method of case class
}
and use this from Java to instantiate the ScalaMessage class w/o problems:
// Java code
ScalaMessage msg = ScalaMessageHelper.apply(payload);
Unless someone comes up with a more elegant solution, I will extract this as an answer...
Thank you!
I think the problem is that in Java if you do the following:
ScalaMessage msg = new ScalaMessage(payload);
Then you are instantiating ScalaMessage using its raw type. Or in other words, you use ScalaMessage as a non generic type (when Java introduced generics, they kept the ability to treat a generic class as a non-generic one, mostly for backward compatibility).
You should simply specify the type parameters when instantiating ScalaMessage:
// (here T = MyDerivedType, where MyDerivedType must extend SomeBaseType
ScalaMessage<MyDerivedType> msg = new ScalaMessage<>(payload);
UPDATE: After seeing your comment, I actually tried it in a dummy project, and I actually get an error:
[error] C:\Code\sandbox\src\main\java\bla\Test.java:8: cannot find symbol
[error] symbol : constructor ScalaMessage(bla.Wrapper<capture#64 of ? extends bla.SomeBaseType>)
[error] location: class test.ScalaMessage<bla.SomeBaseType>
[error] ScalaMessage<SomeBaseType> msg = new ScalaMessage<SomeBaseType>(payload);
It seems like a mismatch between java generics (that we can emulate through exitsentials in scala ) and scala generics. You can fix this by just dropping the type parameter in ScalaMessage and using existentials instead:
case class ScalaMessage(payload: Wrapper[_ <: SomeBaseType])
and then instantiate it in java like this:
new ScalaMessage(payload)
This works. However, now ScalaMessage is not generic anymore, which might be a problem if you want use it with more refined paylods (say a Wrapper<? extends MyDerivedType>).
To fix this, let's do yet another small change to ScalaMessage:
case class ScalaMessage[T<:SomeBaseType](payload: Wrapper[_ <: T])
And then in java:
ScalaMessage<SomeBaseType> msg = new ScalaMessage<SomeBaseType>(payload);
Problem solved :)
What you are experiencing is the fact that Java Generics are poorly implemented. You can't correctly implement covariance and contravariance in Java and you have to use wildcards.
case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T])
If you provide a Wrapper[T], this will work correctly and you'll create an instance of a ScalaMessage[T]
What you would like to do is to be able to create a ScalaMessage[T] from a Wrapper[K] where K<:T is unknown. However, this is possible only if
Wrapper[K]<:Wrapper[T] for K<:T
This is exactly the definition of variance. Since generics in Java are invariant, the operation is illegal. The only solution that you have is to change the signature of the constructor
class ScalaMessage[T](wrapper:Wrapper[_<:T])
If however the Wrapper was implemented correctly in Scala using type variance
class Wrapper[+T]
class ScalaMessage[+T](wrapper:Wrapper[T])
object ScalaMessage {
class A
class B extends A
val myVal:Wrapper[_<:A] = new Wrapper[B]()
val message:ScalaMessage[A] = new ScalaMessage[A](myVal)
}
Everything will compile smoothly and elegantly :)
I'm using Hibernate validator and trying to create a little util class:
public class DataRecordValidator<T> {
public void validate(Class<T> clazz, T validateMe) {
ClassValidator<T> validator = new ClassValidator<T>(clazz);
InvalidValue[] errors = validator.getInvalidValues(validateMe);
[...]
}
}
Question is, why do I need to supply the Class<T> clazz parameter when executing new ClassValidator<T>(clazz)? Why can't you specify:
T as in ClassValidator<T>(T)?
validateMe.getClass() as in ClassValidator<T>(validateMe.getClass())
I get errors when I try to do both options.
Edit: I understand why #1 doesn't work. But I don't get why #2 doesn't work. I currently get this error with #2:
cannot find symbol
symbol : constructor ClassValidator(java.lang.Class<capture#279 of ? extends java.lang.Object>)
location: class org.hibernate.validator.ClassValidator<T>
Note: Hibernate API method is (here)
Because T is not a value - it's just a hint for the compiler. The JVM has no clue of the T. You can use generics only as a type for the purposes of type checking at compile time.
If the validate method is yours, then you can safely skip the Class atribute.
public void validate(T validateMe) {
ClassValidator<T> validator =
new ClassValidator<T>((Class<T>) validateMe.getClass());
...
}
But the ClassValidator constructor requires a Class argument.
Using an unsafe cast is not preferred, but in this case it is actually safe if you don't have something like this:
class A {..}
class B extends A {..}
new DataRecordValidator<A>.validate(new B());
If you think you will need to do something like that, include the Class argument in the method. Otherwise you may be getting ClassCastException at runtime, but this is easily debuggable, although it's not quite the idea behind generics.
Because ClassValidator is requiring a Class object as its parameter, NOT an instance of the class in question. Bear in mind you might be able to do what you're trying to do with this code:
ClassValidator<? extends T> validator = new ClassValidator<? extends T>(validateMe.getClass());