Lambda generic type bounds - java

I have the following method:
public <T> T getObjectFromMessage(Class<T> clazz) {
return gson.fromJson(compressor.decompress(message.getJsonInputs(s3)), clazz);
}
I want to pass getObjectFromMessage as a parameter into a lambda that's supplied to me. The lambda can then supply the class of the object that it expects to find in the message, and get an instance of it back. Is there a way to do this without losing the type information?
I can force it to work with casting and some Object bounds, but I'd really like the consumer to know that if it passes in a Class<T> it will get a T back, much like any method with generic bounds.
In the consuming lambda, I'm currently forced to do declaration gymnastics like:
public void consume(Function<Class<Object>, Object> getInputs){
MyType type = (MyType)getInputs.apply(MyType.class);
}
but there are cases where I want to try to parse the inputs, and if I fail, try a different class. The generics really need to be inferred per-call, as a method would.

You can define a custom function interface with a generic method:
interface TypeFunction {
<T> T apply(Class<T> clazz);
}
public void consume(TypeFunction getInputs) {
MyType type = getInputs.apply(MyType.class);
}

Some thoughts on this... does a function that invokes another function add anything?
For example:
<T> T consume(ReadType<T> typeFunction) {
T type = typeFunction.read();
return type;
}
There are generic types being managed in at least 3 entities here:
The class that contains the message string.
The function that deserializes the message string to an object.
The function that calls the deserializer function.
I expect from the question that the Object that holds the message string is also responsible for deserialization? If so you could consider declaring the generic type there. That would prevent the need of passing the type to the deserializer function, for example this could be simplified further:
<T> ReadType<T> readObjectFromMessage(Class<T> clazz) {
return () -> readValue(clazz);
}
I've declared ReadType as:
interface ReadType<T> {
T read();
}
Also implemented a simple test to check outputs and visualise how this might be used:
#Test
public void consumeTypeTest() throws Exception {
String message = "{\"foo\":\"hello\",\"bar\":\"world\"}";
GenericFunctions genericFunctions = new GenericFunctions(message);
ReadType<MyType> myTypeFromMessage = genericFunctions.readObjectFromMessage(MyType.class);
MyType myType = genericFunctions.consume(myTypeFromMessage);
Assert.assertThat(myType, equalTo(new MyType().setFoo("hello").setBar("world")));
}

Related

How to get a generic type which is defined on method in Java?

Question 1:
Suggest I have a example like this:
public <T> void methodA(T req) { // doSth }
psvm(){
ClassA aClass = new ClassA();
aClass.<String>methodA("hello world");
}
then can I get type String in methodA without actually passing String to it?
Question 2:
If the previous example is transformed to this:
public <T> void methodA(Predicate<T> req) { // doSth }
psvm(){
ClassA aClass = new ClassA();
aClass.<String>methodA(item -> "hello world".equals(item));
}
I mean what was passed into methodA is no more a simple object but a lambda expression, also, can I get type String in methodA?
No, it is not possible to determine the generic type of a generic method, due to type erasure. At compile time, the generic type of the method is discarded, and there is no way to get this information at runtime.
public class ClassA {
public <T> void methodA(T req) {
Class<T> genericType = ?; // Impossible to get e.g. Class<String>
// [...]
}
public static void main(){
new ClassA().methodA("hello world");
}
}
There are certain scenarios where generic type information is retained (such as extending a generic class with a specific generic type, e.g. class MyList implements List<String>). However, there is no way to do so for a generic method.
The best you could do, if you needed that information, would be to pass it in (which you stated you didn't want to do):
public <T> void methodA(T req, Class<T> type) {
// [...]
}
Another option, if all you needed was the type of the object passed in as opposed to the type of the generic method, would be to get the class of the object.
public <T> void methodA(T req) {
Class<?> type = req.getClass(); // Assuming req is non-null
// [...]
}
Note that with this option in this specific example, the generic type is no longer being used for anything, so it can be dropped from the method signature. This may not always be the case, such as if multiple parameters or a parameter and the return type needed matching generic types.
public void methodA(Object req)

Without Wildcarded Generic Class Parameter Type Lost In ObservableSet forEach

I am trying to understand the following, and why it might be so:
I have a class:
public abstract class ProducerType<T extends BulkItem> extends SomeClass<T> {
public ObservableSet<ProductType> getProductTypes() {
return productTypes;
}
}
In another class I have a method:
private void buildChildActivities(ProducerType<?> type) {
type.getProductTypes().forEach((ProductType pt) -> {
// do stuff
});
}
I was initially missing the <?> on the ProducerType parameter to this method, so it was:
private void buildChildActivities(ProducerType type) {
which resulted in the type of the members returned in the forEach going missing in the lambda Consumer. The <T> generic has no effect on the method defined in ProducerType or the Set it returns, so I'm wondering why it fails without the wildcard there?
When using generics you are allowed to opt out by not providing a type argument. This is then called a raw type.
The clue now is: By opting out the generics world in a method's signature, this method uses raw types at all. That means that the method type.getProductTypes() now returns a raw ObservableSet inside your buildChildActivities method. This set type now obviously does not contain any type information, so the compiler must assume Object.

How to avoid the use of raw type and use generics instead when the type is unknown?

I have a generic interface for a handler:
public interface EventHandler<T> {
boolean handleEvent(T message);
}
You can implement this interface and process T message. You have to pass an instance of your implementation to an EventDispatcher instance. The class stores internally multiple EventHandler instances of various types.
At some point an event is triggered and the EventDispatcher instance calls the corresponding EventHandler's handleEvent() method and passes a message that is the same type as the EventHandler. The problem is that I don't know which is the exact type, but I am sure that the T message I'm passing to the EventHandler instance have the same "T".
The way I make this call uses raw types and works:
EventHandler handler = getHandler();
Object message = getMessage();
handler.handleEvent(message);
,but I get the warning "Unchecked call to 'handleEvent(T)' as a member of raw type 'EventHandler'".
Is it possible to use generics to avoid the warning?
One possible solution I have thought of is to make a generic wrapper method:
private <T> boolean handleEventGeneric(EventHandler<T> handler, T message) {
return handler.handleEvent(message);
}
and use it:
EventHandler handler = getHandler();
Object message = getMessage();
handleEventGeneric(action.eventHandler, message);
But I don't like the fact that I have to make a wrapper method. Is there a more elegant solution?
It's not possible to remove this warning (or at least not without #SuppressWarning). The only way to get rid of it is by doing 2 things:
Making your code type proof: so basically if the invoking code does not use raw type, you are type safe or the invoking code is using rawtypes and it it's fault if the code end up being no type safe
Add the #SuppressWarning("unchecked") on your code.
The warning is there so that you can easily identify where you have a weakness in terms of type safety, in your code. If you use the annotation correctly, then your code is safe and you're sure of not getting any unpleasant ClassCastException, unless you willingly added an #SuppressWarning("unchecked") in a place where you are actually not all that sure that the type is safe.
See some demo code illustrating my point:
import java.util.HashMap;
import java.util.Map;
public class TestGenerics {
private Map<Class<?>, EventHandler<?>> handlers = new HashMap<Class<?>, TestGenerics.EventHandler<?>>();
public interface EventHandler<T> {
boolean handleEvent(T message);
}
// Here you force the invoker to provide the correct type of event handler
// with the given type of klass
// If he wants to make this fail, then he will have to use rawtype
public <T> void registerHandler(Class<T> klass, EventHandler<T> handler) {
handlers.put(klass, handler);
}
public <T> void handle(T message) {
#SuppressWarnings("unchecked") // Here you can add this annotation since you are forcing any invoker to provide a correct EventHandler
EventHandler<T> handler = (EventHandler<T>) handlers.get(message.getClass());
if (handler != null) {
handler.handleEvent(message);
}
}
public static void main(String[] args) {
TestGenerics test = new TestGenerics();
test.registerHandler(Long.class, new EventHandler<Long>() {
#Override
public boolean handleEvent(Long message) {
System.out.println("Received a long " + message);
return true;
}
});
// Here I use raw type but this also means that I created a weak spot in
// terms of type safety
EventHandler handler2 = new EventHandler<String>() {
#Override
public boolean handleEvent(String message) {
System.out.println("THis will never print " + message);
return false;
}
};
test.registerHandler(Integer.class, handler2); // This is where the
// problem comes from
test.handle(3L); // OK
test.handle(1); // ClassCastException
}
}
As warning suggest you have genric type safety problem, which is very easy to handle with proper diamond operator before addressing the inherited generic types with in other class.
For instance
public class Parent<R, V> {
...
public class Child<T, S extends Number> {
...
}
}
Generic type safe declaring
<T, S extends Number> Parent<R, V>.Child<T, S> someMethodCall(...)
The R, V in provided declaration are generic types that referenced with in class/interface which the someMethod exist, in general they can even specify with in method as well.
You could do this:
EventHandler<Object> handler = getHandler();
Object message = getMessage();
handler.handleEvent(message);
It's not safe, but no less safe than what you have now.

Java Generics Value.<SomeValue>

I had an interview test and saw the following code:
EDIT:
public class TestValue {
private Value<SomeValue> defaultValue;
#Test
public void Empty_Value_Has_No_Value() {
Assert.assertFalse(Value.<SomeValue> createEmptyValue()
.hasValue());
}
#Test
public void Default_Value_IsEmpty() {
Assert.assertEquals(Value.<SomeValue> createEmptyValue(),
defaultValue);
}
#Test
public void Non_Empty_Value_Has_Value() {
Assert.assertTrue(new Value<SomeValue>(true, new SomeValue())
.hasValue());
}
}
I had never seen Java generic like
Value.<SomeValue>
The test is to implement Value class with the given unit test code above.
I tried to figure out the Value method signature below (need implementation):
public interface Value<T> {
public boolean hasValue();
public Value<T> createEmptyValue();
}
Any one know, please help?
Thank you
EDIT: Should be like this according to answers below #marlon
public class Value<T> {
public boolean hasValue(){}
public static <M> Value<M> createEmptyValue(){}; //need <M>
}
The key syntax to know:
Value.<SomeValue> //ClassName.<Type>method
is way to invoke static method of a class with parameterized argument.
EDIT: according to #snipes83, syntax to invoke non-static method of a class with parameterized argument.
SomeObject.<Type>method
Value.<SomeValue> it's the way generics are represented for methods.
Using Google Guava's Optional as an example:
Optional<String> email = Optional.<String>of(strEmail);
See Generic Types - Invoking generic methods
Since interfaces cannot declare static methods (shame on you java), just declare your method as static and forget about the interface, like this:
class Value<T> {
public static <T> Value<T> createEmptyValue(){
return null;
}
}
Look at the class Test with the method getEmptyList below:
public class Test {
public <T> List<T> getEmptyList() {
return new ArrayList<T>();
}
}
It returns an empty List containing objects of type T.
If you use Test like this
Test t = new Test();
List<Integer> list = t.getEmptyList();
Then the type inference mechanism is able to infer the type parameter based on the variable type.
However if you need to use the return value of getEmptyList within a method invocation expression like in the following example where the method printList expects a single argument of type List<Integer>, then the type can not be infered from any variable type.
public void printList(List<Integer> list) {
for (int i : list) {
System.out.print(i);
}
}
printList(t.getEmptyList()); // This will FAIL.
In this case you need to specify the type using the following:
printList(t.<Integer>getEmptyList());
1) This is how generic methods are invoked. Refer >> http://docs.oracle.com/javase/tutorial/java/generics/methods.html
2) <SomeValue> in Value.<SomeValue> is optional. Compiler can infer the type. This is called TypeInference. Refer >> http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html
Answer Updated:
3) Value.<SomeValue> createEmptyValue() is right and Value.<SomeValue>createEmptyValue() is right too. Both ways are legal. Just tested it. Didn't notice before.
Although Value is itself obviously typed ( based on the instance variable type of Value<SomeValue>), the static createEmptyValue() method is also typed.
A reasonable assumption, if naming conventions have been adhered to, is that SomeValue extends (or implements) Value.
Although there us no one correct answer, a likely possibility for the signature of Value is:
public class Value<T extend Value> {
public static <V extends Value> V createEmptyValue() {
// some impl
}
}

How to pass a parameterized class as an argument

My goal is to develop a class that can output an object of a specified class.
public class GetMe<T> {
public T get() {
Object obj = generateObject();
return (T) obj;
}
}
Now, I know this isn't possible due to erasure. So, we can pass in a class instance and use that to cast.
public class GetMe<T> {
public GetMe<T>(Class<T> clazz) {
this.clazz = clazz;
}
public T get() {
Object obj = generateObject();
return clazz.cast(obj);
}
}
This works great! As long as the class isn't parameterized. If it is, then I've got a problem.
I'm not allowed to use List<String>.class. If I pass in a ParameterizedType (which in itself is difficult to generate), there's no cast method to use.
Is there a way out of this quagmire?
I think super type tokens may solve this problem for you.
The problem with List<String> is that, because of erasure, it would at runtime indistinguishable from any other List<?>. The easiest way around this is to create a new class or interface which has the generic part "fixed", like
public interface StringList extends List<String> {
/* nothing to see here */
}
This way you have a type token (the StringList.class object) which you can pass around at runtime and specifies exactly what you want, but without the need for generics at runtime.
Here is just a small idea. I'm not really sure if it will fit in your context but nevertheless:
public class GetMe<T>
{
public List<T> getList() {
#SuppressWarnings("unchecked")
List<T> result = (List<T>) new LinkedList();
return result;
}
}
Cheers!
The first problem is how you plan to instantiate a List object. If you disclose more of what you are trying to build, we may be able to help you better.
You may want to use Type instead of Class. Type can represent all generic types, although it's not pleasant to work with.
abstract public class GetMe<T>
{
Type type;
public GetMe<T>(Type type)
{
this.type = type;
}
}
Another problem is how to create a generic type like List<String>. The "super type token" looks neat in syntax, in reality it's basically
static class XX extends TypeReference<List<String>>{}
....
Type typeListString = Util.extract(XX.class);
I would much prefer this way
List<String> f;
Type typeListString = getDeclaredField("f").getGenericType();
Actually, many of these frameworks that do fancy runtime generic magics are working on instance fields only.
I think the confusion comes from the fact that you're trying to create an object from List<> which in face it an interface, not an object.
So no matter what you'd try, you just can't create an instance of List<> , (interfaces aren't actual classes, and don't have constructors)
Try using a constraint to avoid having interfaces put in the declaration:
public class GetMe<T extends Object>
This will guarantee that T is an actual class and not an interface.

Categories

Resources