2015-07-29 5 views
1

Я читаю строку JSON и сделать его в объект, используя код SCALA:Gson ошибка: JsonSyntaxException когда Json есть карта

val myInstance = (new Gson()).fromJson(t, classOf[myClass]) 

Все работает отлично, пока я не добавил хэш-карту в классе «MyClass». Тогда для следующего входа Json (друзья являются HashMap)

{"pId":"P:12345","name":"Dan Brown","friends":{"{\"firstname\":\"John\",\"lastname\":\"Smith\"}":1.0}} 

Тогда я получил следующее сообщение об ошибке в «FirstName» атрибут, как показано ниже. Кто-нибудь есть идеи? Большое спасибо!

15/07/29 08:43:05 ERROR Executor: Exception in task 0.0 in stage 0.0 (TID 0) 
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 51 
    at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:176) 
    at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40) 
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:186) 
    at com.google.gson.internal.bind.MapTypeAdapterFactory$Adapter.read(MapTypeAdapterFactory.java:145) 

и вот MyCLASS класс:

public final class myClass extends implements Serializable { 

    private static final long serialVersionUID = 11271827L; 

    private String pId; 
    private String name; 
    private List<MyPet> pets = new ArrayList<MyPet>(); 
    private Map<MyName, Double> friends = new HashMap<MyName, Double>(); 
     : 
    //some getter/setter here 
} 

и вот Myname класс:

public class MyName { 

    private String firstname; 
    private String lastname; 

    /** 
    * 
    * @return the Json string 
    */ 
    public final String toJsonString() { 
     return (new Gson()).toJson(this); 
    } 

    @Override 
    public final String toString() { 
     return toJsonString(); 
    } 
} 
+0

Это '' {\ "firstname \": \ "John \", \ "lastname \": \ "Smith \"} "' является строкой JSON. Что вы пытаетесь десериализовать? Покажите нам, что такое 'myClass'. –

+0

Обратите внимание на разницу между полем 'name' и поле' firstname'. См. Обратную косую черту перед цитатами вокруг 'firstname'? Это строка в json-входе. Я предполагаю, что вы не указываете тип карты, т. Е. 'HashMap '. –

+0

Я добавил определение myClass выше. Благодаря! – Edamame

ответ

0

в формате JSON, ключ карты должна быть строка. в вашем случае вы используете MyName в качестве ключа. поэтому json parser использует MyName#toString() для преобразования в строку.

Мое предложение является правильным MyName#toString() реализации и обеспечить статический метод MyName valueOf(String) в MyName классе

, например:

class MyName{ 
    private String firstName; 
    private String lastName; 

    // getters and setters 

    @Override 
    public String toString(){ 
     return firstName+" "+lastName; 
    } 

    public static MyName valueOf(String str){ 
     int space = str.lastIndexOf(' '); 
     if(space==-1) 
      throw new IllegalArgumentException(); 
     MyName myName = new MyName(); 
     myName.setFirstName(str.subString(0, space)); 
     myName.setLastName(str.subString(space+1)); 
     return myName; 
    } 
} 

здесь valueOf и toString реализации должны быть совместимы.

выше код предполагает, что нет места в lastName

+0

Спасибо большое! Я добавил класс MyName выше. Он уже переопределяет метод toString, не так ли? Не могли бы вы подробнее рассказать о «предоставлении статического метода MyName valueOf (String) в классе MyName»? Спасибо! – Edamame

+0

Что будет делать метод 'valueOf'? Почему ты так думаешь? –

+0

это java-соглашение, чтобы иметь статический метод 'valueOf (String)' для построения из строкового представления. например, см. 'Integer.valueOf (String)', 'Float.valueOf (String)' и т. д. json parsers используют это соглашение для преобразования строкового представления в конкретный объект. –

0

Что вы делаете, это плохая идея. Не предоставляйте сложные структуры объектов, представленные в виде строк в именах JSON.

Вот решение тем не менее. Обеспечить и зарегистрировать пользовательские JsonDeserializer

Gson gson = new GsonBuilder().registerTypeAdapter(MyName.class, new KeyDeserializer()).create(); 
... 
class KeyDeserializer implements JsonDeserializer<MyName> { 
    private Gson gson = new Gson(); 

    @Override 
    public MyName deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     return gson.fromJson(json.getAsString(), MyName.class); 
    } 
} 

JsonElement будет содержать строку JSON (это будет JsonPrimitive). Вызов getAsString на нем будет возвращать String значение, Java

{"firstname":"John","lastname":"Smith"} 

Затем мы используем отдельный экземпляр Gson десериализации, что в MyName например, с поведением по умолчанию. Нам нужен этот второй экземпляр Gson, потому что оригинал уже зарегистрировал KeyDeserializer для пользовательской десериализации.

Смежные вопросы