2011-06-13 3 views
11

JSON 개체에 메서드로 전달 될 때 jsonKey이 포함되어 있으면 아래 코드가 잘 작동합니다. 내가 궁금해 ... 열쇠의 대소 문자를 구분하지 않는 표현에 할당 된 값을 얻는 방법이 있다면?GSON : Json에서 대소 문자를 구분하지 않는 요소를 얻는 방법?

예 :

public String getOutputEventDescription(JsonElement outputEvent) throws ParserException { 
    return retrieveString(outputEvent, DESCRIPTION); 
} 

는 설명이 "설명", "설명"또는 "설명"으로 정의되어 있는지 여부에 관계없이 작동합니다

protected String retrieveString(JsonElement e, String jsonKey) throws ParserException { 

JsonElement value = e.getAsJsonObject().get(jsonKey); 

if (value == null) { 
    throw new ParserException("Key not found: " + jsonKey); 
} 

if (value.getAsString().trim().isEmpty()) { 
    throw new ParserException("Key is empty: " + jsonKey); 
} 

return e.getAsJsonObject().get(jsonKey).getAsString(); 
} 

답변

5

불행하게도이있을 것 같지 않습니다 현재 구현에서이 작업을 수행 할 수 있습니다. Gson 소스를보고 더 구체적으로 JsonObject 구현을 살펴보면 기본 데이터 구조가 연결된 해시 맵이라는 것을 알 수 있습니다. get 호출은 맵의 get을 호출하기 만하면됩니다. 그러면 map의 해시 코드와 equals 메소드를 사용하여 찾고있는 객체를 찾습니다.

유일한 방법은 키의 명명 규칙을 적용하는 것입니다. 가장 쉬운 방법은 모든 키를 소문자로 만드는 것입니다. 대소 문자가 혼합 된 키가 필요하다면 jsonKey.toLowerCase()를 호출하는 대신 키를 변형하는보다 복잡한 알고리즘을 작성해야합니다.

8

불행히도 GsonBuilder으로 FieldNamingStrategy을 등록하는 것은 Java 필드 이름에서 JSON 요소 이름까지 반대 방향으로 만 변환되기 때문에 그리 좋지 않을 것입니다. 귀하의 목적에 합리적으로 사용할 수 없습니다.

(세부 사항 : members라는 번역 요청의 결과는 번역 된 이름이 LinkedHashMap<String, JsonElement>이있는 JsonObject에서 관련 JSON 요소를 가져 오는 데 사용됩니다 FieldNamingStrategy.translateName(Field)에서 종료

, 맵핑 JSON 요소 이름 연관된 값. 번역 된 이름 membersget(String) 메소드의 파라미터로서 사용하고 GSON은 마지막 통화가 대소 문자를 구별하게 할하기위한 메커니즘을 제공하지 않는다.

members지도호출로 채워져은 Streams.parseRecursive(JsonReader)으로, JsonReader에서 검색된 JSON 요소 이름을 '구성원'의 키로 사용합니다. (JsonReader은 이스케이프 문자 '\'가있는 경우를 제외하고는 JSON에서와 똑같은 문자를 사용합니다.)이 호출 스택에서 Gson은 members을 채우는 데 사용되는 키에 대한 메커니즘을 제공하지 않습니다. 모두 소문자 또는 모두 대문자로 작성하십시오.

같은 방법으로 FieldNamingPolicy 작동합니다.)

합리적인 해결책은 간단하게 다음과 같은 라인을 따라, 사용자 정의 디시리얼라이저를 사용할 수 있습니다.

input.json :

[ 
{"field":"one"}, 
{"Field":"two"}, 
{"FIELD":"three"}, 
{"fIElD":"four"} 
] 

푸.자바 :

import java.io.FileReader; 
import java.lang.reflect.Type; 
import java.util.Map.Entry; 

import com.google.gson.Gson; 
import com.google.gson.GsonBuilder; 
import com.google.gson.JsonDeserializationContext; 
import com.google.gson.JsonDeserializer; 
import com.google.gson.JsonElement; 
import com.google.gson.JsonObject; 
import com.google.gson.JsonParseException; 

public class Foo 
{ 
    public static void main(String[] args) throws Exception 
    { 
    GsonBuilder gsonBuilder = new GsonBuilder(); 
    gsonBuilder.registerTypeAdapter(MyClass.class, new MyTypeAdapter()); 
    Gson gson = gsonBuilder.create(); 
    MyClass[] myObjects = gson.fromJson(new FileReader("input.json"), MyClass[].class); 
    System.out.println(gson.toJson(myObjects)); 
    } 
} 

class MyClass 
{ 
    String field; 
} 

class MyTypeAdapter implements JsonDeserializer<MyClass> 
{ 
    @Override 
    public MyClass deserialize(JsonElement json, Type myClassType, JsonDeserializationContext context) 
     throws JsonParseException 
    { 
    // json = {"field":"one"} 
    JsonObject originalJsonObject = json.getAsJsonObject(); 
    JsonObject replacementJsonObject = new JsonObject(); 
    for (Entry<String, JsonElement> elementEntry : originalJsonObject.entrySet()) 
    { 
     String key = elementEntry.getKey(); 
     JsonElement value = originalJsonObject.get(key); 
     key = key.toLowerCase(); 
     replacementJsonObject.add(key, value); 
    } 
    return new Gson().fromJson(replacementJsonObject, MyClass.class); 
    } 
} 

또는 먼저 원시 JSON을 처리 할 수는 모두 소문자 또는 모두 대문자 같은 경우로 요소 이름을 모두 변경합니다. 그런 다음 변경된 JSON을 Gson으로 전달하여 직렬화 해제하십시오. 물론 JSON 처리 속도가 느려집니다.

프로젝트의 Gson 코드를 변경할 수 있다면 name = nextString((char) quote);JsonReader으로 호출하는 것이 가장 효율적인 결과로 변경 될 것입니다. nextString(char) 또한 JSON 요소 값을 가져 오는 데 사용되기 때문에 이름을 가져 오는 데 필요한 복사본을 만든 다음 요소 이름을 모두 대문자 또는 소문자로 변경하기 위해 작은 변경을 가할 것입니다. 물론이 접근법은 프로젝트를 Gson의 한 릴리즈로 고정시킵니다. 그렇지 않으면 새로운 Gson 릴리스로 업그레이드하기 위해이 변경을 반복해야합니다.

Jackson의 경우 상황은 불행하게도 비슷합니다. PropertyNamingStrategy이있는 번역은 불행히도 같은 방식으로 작동합니다. 즉, Java 필드 이름에서 JSON 요소 이름으로 변환합니다. 사용 가능한 JsonParser.Feature 변경 사항 중 어느 것도 JsonParser을 사용자 정의하여 JSON 요소 이름을 모두 대문자 또는 모두 소문자로 만들지 않습니다.

6

나는 비슷한 문제에 직면했다. 나는이 문제를 해결하기 위해 이것을했다. (모든 키를 해당 소문자 버전으로 대체했으며 일치하는 클래스에 소문자 필드가 모두 있음). 희망이 도움이됩니다.

input = input.replaceAll("\\s",""); 
     Matcher m = Pattern.compile("\"\\b\\w{1,}\\b\"\\s*:").matcher(input); 
     StringBuilder sanitizedJSON = new StringBuilder(); 
     int last = 0; 
     while (m.find()) { 
      sanitizedJSON.append(input.substring(last, m.start())); 
      sanitizedJSON.append(m.group(0).toLowerCase()); 
      last = m.end(); 
     } 
     sanitizedJSON.append(input.substring(last)); 

     input = sanitizedJSON.toString(); 
+1

모든 공백을 삭제하는 이유가 확실하지 않은 경우를 제외하고 위대한 방법입니다. – Rooster242

관련 문제