1

It'll throw null exception when I use new TypeReference<T>() {} in the lambda function and the T is from outer functin generic paramter. But it's OK when this statement is directly write in function.

  • Java version: 8
  • Jackson version: 2.12.5

There're minimum runnable code examples blow.

This will get java.lang.IllegalArgumentException: Unrecognized Type: [null]

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;

public class Main {

    public static void main(String[] args) {
        String test = "[\"test\"]";

        List<String> strings = getObjectConfig(test, new ArrayList<>());
        System.out.println(strings);
    }

    public static <T> T getObjectConfig(String key, T defaultValue) {
        return getCommon(
                key,
                v -> {
                    if (Objects.isNull(v)) {
                        return defaultValue;
                    } else {
                        try {
                            return new ObjectMapper().readValue(v, new TypeReference<T>() {});
                        } catch (JsonProcessingException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
        );
    }

    private static <T> T getCommon(String key, Function<String, T> transFunc) {
        try {
            String value = key;
            return transFunc.apply(value);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

But this is OK.

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) throws Exception {
        String test = "[\"test\"]";

        List<String> strings = getObjectConfig(test, new ArrayList<>());
        System.out.println(strings);
    }

    private static <T> T getObjectConfig(String key, T defaultValue) throws JsonProcessingException {
        return new ObjectMapper().readValue(key, new TypeReference<T>() {});
    }

}
callofdutyops
  • 318
  • 3
  • 9

2 Answers2

0

After several tests, I was able to reproduce your bug with Java 11. Please note that everything was working fine with Java 17.

First of all, I found this post that is about a similar problem.

Then, to solve the problem I specifically passed the class I follow:

public static void main(String[] args) {
    String test = "[\"test\"]";

    List<String> strings = getObjectConfig(test, new ArrayList<String>(), ArrayList.class);
    System.out.println(strings);
}

public static <T> T getObjectConfig(String key, T defaultValue, Class<T> clazz) {
    return getCommon(
            key,
            v -> {
                if (Objects.isNull(v)) {
                    return defaultValue;
                } else {
                    try {
                        return new ObjectMapper().readValue(v, clazz);
                    } catch (JsonProcessingException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
    );
}

private static <T> T getCommon(String key, Function<String, T> transFunc) {
    try {
        String value = key;
        return transFunc.apply(value);
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

Instead of using a TypeReference, I used a Class.

Raphallal
  • 122
  • 1
  • 12
  • Thanks, this DOES work. But a duplicated type paramter has to be added in the function signature and there'll be an unchecked warning. :-/ I'm wondering whether there's a perfect solution. – callofdutyops Mar 22 '23 at 12:04
  • With the way generics are implemented in Java, I'm not sure that what you are looking for is possible. The warning comes from the implicit cast from `ArrayList` to `ArrayList` – Raphallal Mar 22 '23 at 12:46
0

You can fix it by changing it to:

return new ObjectMapper().readerFor(defaultValue.getClass()).readValue(v);

note: if you try some objects that can't be strongly converted by LinkedHashMap, Then you can see that your second use case will also report an error. And this is caused by java type erasure.

yichen
  • 1
  • 1