2015-05-07 27 views
3

致力於爲處理物理建築物的應用程序構建模型。使用Jackson在具有未知鍵名的同一文件中處理多個JSON對象

理想情況下,我們會想是這樣的:

市有多個辦事處,其中有多個房間,其中有屬性。

我們使用jackson來解析從API數據源接收到的JSON負載,它看起來有點不同於我見過的示例。

我們得到的格式是:

{ 
"CityName1": 
    { "OfficeName1": 
     [ 
      {"name": RoomName1, "RoomProperty2": RoomValue1}, 
      {"name": RoomName2, "RoomProperty2": RoomValue2} 
     ] 
    }, 
    { "OfficeName2": [{...}]}, 
    { "OfficeNameX" : [{...}] }, 
"CityName2": {...}, 
"CityNameN": {...}} 

Java類:

public class City { 
    private Map<String, Object> additionalProperties = new HashMap<String, Object(); 

    private List<Office> _offices = new ArrayList<Office>(); 

    @JsonAnyGetter 
    public Map<String, Object> getAdditionalProperties() { 
    return this.additionalProperties; 
    } 

    @JsonAnySetter 
    public void setAdditionalProperty(String name, Object value) 
     throws IOException { 
    _cityName = name; 
    String officeJson = _mapper.writeValueAsString(value); 
    StringBuilder sb = new StringBuilder(officeJson); 
    _offices.add(_mapper.readValue(officeJson, Office.class)); 
    this.additionalProperties.put(name, value); 
    } 
} 

public class Office { 

    private String _officeName; 

    private static final ObjectMapper _mapper = new ObjectMapper(); 

    private Map<String, Object> additionalProperties = new HashMap<String, Object>(); 

    private List<Room> _rooms = new ArrayList<Room>(); 

    @JsonAnyGetter 
    public Map<String, Object> getAdditionalProperties() { 
    return this.additionalProperties; 
    } 

    @JsonAnySetter 
    public void setAdditionalProperty(String name, Object value) 
     throws IOException { 
    _officeName = name; 
    String roomJson = _mapper.writeValueAsString(value); 
    Room[] rooms = _mapper.readValue(roomJson, Room[].class); 
    _rooms.addAll(Arrays.asList(rooms)); 
    this.additionalProperties.put(name, value); 
    } 

    public List<Room> getRooms() { 
    return _rooms; 
    } 

    public void setRooms(List<Room> rooms) { 
    _rooms = rooms; 
    } 
} 

public class Room { 

    private static final String NAME = "name"; 
    private static final String PROP_2 = "RoomProperty2"; 

    @JsonProperty(PROP_2) 
    private String _propertyTwo; 

    @JsonProperty(NAME) 
    private String name; 

    @JsonProperty(PROP_2) 
    public String getPropertyTwo() { 
    return _propertyTwo; 
    } 

    @JsonProperty(PROP_2) 
    public void setPropertyTwo(String propTwo) { 
    _propertyTwo = propTwo; 
    } 

    public String getName() { 
    return name; 
    } 

    public void setName(String name) { 
    this.name = name; 
    } 

那麼我將如何去與傑克遜解析呢?目前,我使用@JsonAnySetter來獲取名稱,並將其保存爲城市或辦公室名稱,然後將發送給JsonAnySetter的值發送到相應的嵌套類。真正的問題是獲得城市辦事處名單。當使用mapper.readvalues(String,Office.class)時,我只返回每個城市最後一個辦公室的迭代器。任何想法傢伙?

對不起,如果這似乎令人困惑!願意回答我創建的任何問題。

感謝您的幫助!

+2

像往常一樣,顯示涉及的Java類在這裏是必要的。 – StaxMan

+0

新增課程。問題是_offices只包含1個辦公室,當它包含N. – Ajayc

+0

一個簡單的建議:不要寫json,重新讀取,試試'ObjectMapper.convertValue(value,Office.class')。同樣的事情,更簡單,更多有效。 – StaxMan

回答

3

我認爲最好的解決方案是在這裏編寫自己的deserialiser,因爲你的JSON文檔並不能很好地映射到你想要的類結構。

下面的解決方案讀取每個城市作爲一個Map<String, List<Room>>和城市作爲一個Map<String, City>的集合,然後創建解串器內從這些CityOffice對象。

Room.java是一樣的你,這裏是休息:

Cities.java

@JsonDeserialize(using=CitiesDeserializer.class) 
public class Cities implements Iterable<City> { 

    private final List<City> cities; 

    public Cities(final List<City> cities) { 
     this.cities = cities; 
    } 

    public Cities() { 
     this.cities = new ArrayList<>(); 
    } 

    public List<City> getCities() { 
     return cities; 
    } 

    @Override 
    public Iterator<City> iterator() { 
     return cities.iterator(); 
    } 
} 

CitiesDeserialiser.java

public class CitiesDeserializer extends JsonDeserializer<Cities> { 
    private static final TypeReference<Map<String, City>> TYPE_REFERENCE = new TypeReference<Map<String, City>>() {}; 

    @Override 
    public Cities deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException { 
     final Map<String, City> map = jp.readValueAs(TYPE_REFERENCE); 
     List<City> cities = new ArrayList<>(); 
     for(Map.Entry<String, City> entry : map.entrySet()) { 
      City city = entry.getValue(); 
      city.setName(entry.getKey()); 
      cities.add(city); 
     } 
     return new Cities(cities); 
    } 
} 

市.java

@JsonDeserialize(using=CityDeserialzer.class) 
public class City { 

    private String name; 

    private List<Office> offices; 

    // Setters and getters 
} 

CityDeserializer.java

public class CityDeserialzer extends JsonDeserializer<City> { 
    private static final TypeReference<Map<String, List<Room>>> TYPE_REFERENCE = new TypeReference<Map<String, List<Room>>>() {}; 

    @Override 
    public City deserialize(final JsonParser jp, final DeserializationContext ctxt) throws IOException { 
     final Map<String, List<Room>> map = jp.readValueAs(TYPE_REFERENCE); 
     List<Office> offices = new ArrayList<>(); 
     for(Map.Entry<String, List<Room>> entry : map.entrySet()) { 
      Office office = new Office(); 
      office.setName(entry.getKey()); 
      office.setRooms(entry.getValue()); 
      offices.add(office); 
     } 
     City city = new City(); 
     city.setOffices(offices); 
     return city; 
    } 
} 

辦公室。java的

public class Office { 

    private String name; 

    private List<Room> rooms; 

    // Setters and getters 
} 

而這裏的測試表明,它的工作原理:

JSON:

{ 
    "CityName1": { 
     "OfficeName1": [ { 
       "name": "RoomName1", 
       "RoomProperty2": "RoomValue1" 
      }, { 
       "name": "RoomName2", 
       "RoomProperty2": "RoomValue2" 
      } ], 
     "OfficeName2": [ { 
       "name": "RoomName3", 
       "RoomProperty2": "RoomValue3" 
      }, { 
       "name": "RoomName4", 
       "RoomProperty2": "RoomValue4" 
      } ] 
    }, 
    "CityName2": { 
     "OfficeName3": [ { 
       "name": "RoomName5", 
       "RoomProperty2": "RoomValue5" 
      }, { 
       "name": "RoomName6", 
       "RoomProperty2": "RoomValue6" 
      } ], 
     "OfficeName4": [ { 
       "name": "RoomName7", 
       "RoomProperty2": "RoomValue7" 
      }, { 
       "name": "RoomName8", 
       "RoomProperty2": "RoomValue8" 
      } ] 
    } 
} 

Test.java

public class Test { 

    public static void main(String[] args) { 
     String json = ... 
     ObjectMapper mapper = new ObjectMapper(); 
     Cities cities = mapper.readValue(json, Cities.class); 
     for(City city : cities) { 
      System.out.println(city.getName()); 
      for(Office office : city.getOffices()) { 
       System.out.println("\t" + office.getName()); 
       for(Room room : office.getRooms()) { 
        System.out.println("\t\t" + room.getName()); 
        System.out.println("\t\t\t" + room.getPropertyTwo()); 
       } 
      } 
     } 
    } 
} 

輸出:

CityName1 
    OfficeName1 
     RoomName1 
      RoomValue1 
     RoomName2 
      RoomValue2 
    OfficeName2 
     RoomName3 
      RoomValue3 
     RoomName4 
      RoomValue4 
CityName2 
    OfficeName3 
     RoomName5 
      RoomValue5 
     RoomName6 
      RoomValue6 
    OfficeName4 
     RoomName7 
      RoomValue7 
     RoomName8 
      RoomValue8 
+0

這可能會起作用另一種方法可能會稍微少一些:使用'Converter',通過'@JsonDeserializer(converter = MyConverter.class)'(和/或相同的對於'@ JsonSerialize') - 這樣,你可以讓傑克遜做一半的工作,綁定到'JsonNode','Map','List ',然後你從那個Java類型轉換成實際類型,做任何需要的結構轉換。 – StaxMan

相關問題