Десериализация map через GSON

0
25 июн 2015 08:16
Всем привет! столкнулся с такой проблемой: не удается десериализовать JSON вида "{"rules": {"referencePoints": {"0": "T:c.ref_arr"}}}". У объекта "referencePoints" интересует в данном случае только поле "key". Результат = null. Я так понимаю, что-то упустил в классе RulesTest?


package TmpTest.TmpTestGsonTest;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.testng.annotations.Test;

public class RulesTest {

    @Test
    public void rulesTest() {


        String jsonString = "{\"rules\": {\"referencePoints\": {\"0\": \"T:c.ref_arr\"}}}";
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(ReferencePoints.class, new ReferencePointDeserializer())
                .create();
        Rules rules = gson.fromJson(jsonString, Rules.class);

        gson = new GsonBuilder()
                .setPrettyPrinting()
                .create();
        System.out.print(gson.toJson(rules));

    }
}


Класс Rules имеет всего одно поле:
package TmpTest.TmpTestGsonTest;

public class Rules {
    ReferencePoints referencePoints;
}



Класс ReferencePoints:

package TmpTest.TmpTestGsonTest;

public class ReferencePoints {

    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
}



Кастомный десериализатор, т.к. GSON из коробки не поимает map-объекты:

package TmpTest.TmpTestGsonTest;

import com.google.gson.*;

import java.lang.reflect.Type;
import java.util.Map;

public class ReferencePointDeserializer implements JsonDeserializer<Object> {

    @Override
    public ReferencePoints deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException {
        ReferencePoints referencePoints = new ReferencePoints();
        JsonObject jsonObject = (JsonObject) element.getAsJsonObject().get("referencePoints");

        for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet())
        {
            referencePoints.setId(entry.getKey());
        }
        return referencePoints;
    }
}


Отдельно строку "{"referencePoints": {"0": "T:c.ref_arr"}}" десериализовать удается:

package TmpTest.TmpTestGsonTest;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.testng.annotations.Test;

public class ReferencePointsTest {

    @Test
    public void gsonTest(){

        String string = "{\"referencePoints\": {\"0\": \"T:c.ref_arr\"}}";
        GsonBuilder builder = new GsonBuilder();
        Gson gson = builder.registerTypeAdapter(ReferencePoints.class, new ReferencePointDeserializer()).create();
        ReferencePoints referencePoints = gson.fromJson(string, ReferencePoints.class);

        gson = new GsonBuilder()
                .setPrettyPrinting()
                .create();
        System.out.print(gson.toJson(referencePoints));

    }
}

Ответов: 5

2
25 июн 2015 09:39
Quote:
JsonObject jsonObject = (JsonObject) element.getAsJsonObject().get("referencePoints");

1) Естественно у вас ничего работать не будет. Вы регистрируете обработчик для класса ReferencePoints, который в итоге получает строку "{\"0\": \"T:c.ref_arr\"}", а потом пытаетесь у него получить поле "referencePoints". А в рабочем примере вы насильно заставляете невалидную строку "{\"referencePoints\": {\"0\": \"T:c.ref_arr\"}}" парситься вашим обработчиком. "{\"referencePoints\": {\"0\": \"T:c.ref_arr\"}}" это не ReferencePoints, это Rules. Зарегистрирйте обработчик для класса Rules и будет вам счастье.

2) Не вижу проблем у гсона с мапами:
public static void main(String[] args) {
		
	Map<String, Integer> map = new HashMap<>();
	map.put("qwe", 42);
	map.put("rty", 43);
	System.out.println(map);			// {rty=43, qwe=42}
		
	Gson gson = new Gson();
		
	String s = gson.toJson(map);
	System.out.println(s);				// {"rty":43,"qwe":42}
		
	Type type = new TypeToken<Map<String,Integer>>() {}.getType();
	Map<String, Integer> map2 = gson.fromJson(s, type);
	System.out.println(map2);			// {rty=43, qwe=42}
}


P.S. Учитесь разбираться в своём собственном коде и дебажить свои программы. Добавили бы логов или обычных System.out.println() в десериализатор. Посмотрели бы, что именно вам туда приходит. Всё бы сразу понятно стало.
0
25 июн 2015 13:59
Quote:
У вас тут много камней предкновения, а не только левый обработчик. Может на кошках потренируетесь пока?


Спасибо! Переделал. Рабочий вариант:

public class Rules {
        Map<String,String> referencePoints;
        Boolean isDefault;
    }


public class RulesTest {

    @Test
    public void test(){
            String s = "{\"referencePoints\": {\"0\": \"T:c.ref_arr\", \"1\": \"T:d.ref_arr\"}, \"isDefault\": true}";
            Gson gson = new Gson();
            Rules rules = gson.fromJson(s, Rules.class);
        System.out.println(rules.referencePoints + "\n" + rules.isDefault);
    }
}


Поле "isDefault" изначально выкинул для упрощения.
0
25 июн 2015 09:01
Quote:
Кастомный десериализатор, т.к. GSON из коробки не поимает map-объекты:

Заюзайте вместо него Jackson и не парьтесь, по-моему. Или вам обязательно GSON зачем-то нужен?
-1
25 июн 2015 13:07
Quote:
Зарегистрирйте обработчик для класса Rules и будет вам счастье.
- так понимаю в классе "RulesTest", после
registerTypeAdapter(ReferencePoints.class, new ReferencePointDeserializer())
надо
registerTypeAdapter(Rules.class, new RulesDeserializer())
вставить? Как этот RulesDeserializer должен выглядеть? Сейчас по-прежнему возвращает null, ".get("referencePoints")" удалил.
-1
25 июн 2015 12:45
Quote:
А в рабочем примере вы насильно заставляете невалидную строку "{\"referencePoints\": {\"0\": \"T:c.ref_arr\"}}" парситься вашим обработчиком. "{\"referencePoints\": {\"0\": \"T:c.ref_arr\"}}" это не ReferencePoints, это Rules. Зарегистрирйте обработчик для класса Rules и будет вам счастье.

Вот, вот он, мой камень преткновения! Не подскажете, как в данном случае должен выглядеть обработчик для класса Rules и как его зарегистрировать?
Модераторы: Нет
Сейчас эту тему просматривают: Нет