Десериализатор Джексона, затронутый Deadbolt, «ограничить» аннотацию - PullRequest
1 голос
/ 20 мая 2019

Я получаю исключение Could not resolve type id 'path.to.MyClass' as a subtype of [simple type, class java.lang.Object]: no such class found на игровом сервере 2.7 с DeadBolt (2.6.3 и 2.7.0), когда я пытаюсь десериализовать JSON до Map<String, MyClass> внутри действия маршрута с аннотацией @Restrict. Все работает нормально, если удалить эту аннотацию.

MyClass.java


@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "class")
public class MyClass implements Serializable {
    public String name;
    public Integer age;
    public MyClass(){}
    public MyClass(String name, Integer age){
        this.name = name;
        this.age = age;
    }
}

сериализация Map<String, MyClass>

Map<String, MyClass> value = new HashMap<>();
value.put("first", new MyClass("Bob",10));
value.put("second", new MyClass("Rob",20));

ObjectMapper mapper = Json.newDefaultMapper();
        mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, "class");
String json = null;
try {
    json = mapper.writeValueAsString(value);
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

выход

{
  "first":{
    "class":"path.to.MyClass",
    "name":"Bob",
    "age":10
  },
  "second":{
    "class":"path.to.MyClass",
    "name":"Rob",
    "age":20
  }
}

Формат JSON выглядит так из-за обратной совместимости со старым сервером, который использует старый FlexJson.

deserialise

@Restrict({@Group({"Admin"})})
public CompletionStage<Result> action(long id) {
    String json = getJsonFromStorage();
    Map<String, MyClass> result = new HashMap<>();
    try {
        ObjectMapper mapper = new ObjectMapper();
        mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, "class");
        JsonFactory factory = mapper.getFactory();
        JsonParser parser = factory.createParser(new ByteArrayInputStream(json.getBytes(Charset.forName("UTF-8"))));
        JavaType type = mapper.getTypeFactory().constructType(result.getClass());
        t = mapper.readValue(parser, type);
        } catch (IOException e) {
            e.printStackTrace();
        }

    return ok("ok")
}

1 Ответ

0 голосов
/ 29 мая 2019

У меня есть временное решение. Я перезаписываю загрузчик классов для текущего потока в загрузчик классов из play.Environment

public class MyController extends Controller {

    @Inject
    private Environment environment;

    @Restrict({@Group({"Admin"})})
    public CompletionStage<Result> action(long id) {

        Thread.currentThread().setContextClassLoader(environment.classLoader());

        String json = getJsonFromStorage();
        Map<String, MyClass> result = new HashMap<>();
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.enableDefaultTypingAsProperty(ObjectMapper.DefaultTyping.OBJECT_AND_NON_CONCRETE, "class");
            JsonFactory factory = mapper.getFactory();
            JsonParser parser = factory.createParser(new ByteArrayInputStream(json.getBytes(Charset.forName("UTF-8"))));
            JavaType type = mapper.getTypeFactory().constructType(result.getClass());
            t = mapper.readValue(parser, type);
            } catch (IOException e) {
                e.printStackTrace();
            }

        return ok("ok")
    }

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...