2016-04-26 9 views
3

私はいくつかのGSonアノテーションを持つDTOを持っています。
マイproblemeは、これらのアノテーションの値は者協会やステージングまたは生産の私のアプリケーションを実行すると一瞬のために...
一部の環境でGson SerializedNameが変更される

を変更する必要があり、私は別の値で自分のアプリケーションをパッケージ化する必要があると私ということですそれは、春のブートアプリケーションであると私はここで右serializedName

を取るために自分のアプリケーションを伝えるためにspring.profiles.activeを使用したい私は

// Tests 
    // @SerializedName("customfield_10123") 
    // Prod 
    @SerializedName("customfield_10114") 
    private ActionDto action; 
を使用するコードの一種である...これは自動になりたいです

もっと良い方法があるといいですか?ここで

答えて

1

はあなたが望むものを達成することができますどのように非常に粗製の例である:

まず、各可能なプロファイル(名前は何でもかまいませんが、プロファイルは名前でなければなりません)のためのproperyファイルを作成します

application-dev.properties 
application-prod.properties 
... 

あなたは各プロファイルに応じて、各キーに必要な値を持つプロパティを移入:

test=abc.test 
... 

はあなたのPOJOを注釈:

public class Foo { 

    @SerializedName("${test}") 
    private String name; 

    ... 

} 

このような何か、カスタム名を解釈している、あなたのクラスのカスタム・シリアライザを作成します。

public class FooSerializer implements JsonSerializer<Foo> { 

    private static final Pattern PATTERN = Pattern.compile("\\$\\{(.*)\\}"); 
    private static Properties props; 

    static { 
     try { 
      Resource resource = new ClassPathResource(String.format("/application-%s.properties", System.getProperty("spring.profiles.active"))); 
      props = PropertiesLoaderUtils.loadProperties(resource); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public JsonElement serialize(Foo foo, Type type, JsonSerializationContext jsonSerializationContext) { 

     Field[] fields = foo.getClass().getDeclaredFields(); 

     JsonObject object = new JsonObject(); 

     for (Field field : fields) { 
      field.setAccessible(true); 
      String name = field.getName(); 
      if (field.isAnnotationPresent(SerializedName.class)) { 
       String value = field.getAnnotation(SerializedName.class).value(); 
       Matcher matcher = PATTERN.matcher(value); 
       if (matcher.find()) { 
        name = props.get(matcher.group(1)).toString(); 
       } else { 
        name = value; 
       } 
      } 
      try { 
       if (field.get(foo) != null) { 
        object.addProperty(name, field.get(foo).toString()); 
       } 
      } catch (IllegalAccessException e) { 
       e.printStackTrace(); 
      } 
     } 
     return object; 
    } 
} 

今、あなたは自分のカスタム・シリアライザを登録する必要があり、あなたが行ってもいいです:

Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, new FooSerializer()).setPrettyPrinting().create(); 

もちろん、アクティブなプロファイルに従ってプロパティファイルを復元する方が良いかもしれませんが、所定のスニペットで十分なはずです。また、いつでも複数のプロファイルがアクティブである可能性があることを考慮する必要があります。そのシナリオの場合は、プロパティを回復する前に考慮する必要があります。

プロパティの値を常に使用する場合は、正規表現の部分は必要ありません。私は両方のケースを許可するために正規表現を使用しました。

明らかにされていないことがある場合は、私にお知らせください。私は改善を図ります。

は編集:私は非常に良いものを考え出すことができない、逆シリアル化のために

は、ので、ここで私はこれまでOKからだと思うの例ですが、仕事を取得:機能

をインターフェース:

public interface Converter { 

    Object convert(String s); 
} 

デシリアライザ:

public class FooDeserializer implements JsonDeserializer<Foo> { 

    private static final Pattern PATTERN = Pattern.compile("\\$\\{(.*)\\}"); 
    private static Properties props; 
    private static Map<Class, Converter> converterForClass = new HashMap<>(); 

    static { 
     try { 
      Resource resource = new ClassPathResource(String.format("/application-%s.properties", System.getProperty("spring.profiles.active"))); 
      props = PropertiesLoaderUtils.loadProperties(resource); 

      converterForClass.put(Integer.TYPE, s -> Integer.parseInt(s.replace("\"", ""))); 
      converterForClass.put(Double.TYPE, s -> Double.parseDouble(s.replace("\"", ""))); 
      converterForClass.put(String.class, s -> s); 
      converterForClass.put(Long.TYPE, s -> Long.parseLong(s.replace("\"", ""))); 
      converterForClass.put(Boolean.TYPE, s -> Boolean.parseBoolean(s.replace("\"", ""))); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 

    @Override 
    public Foo deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException { 


     Foo foo = new Foo(); 

     JsonObject jobject = (JsonObject) jsonElement; 

     for (Entry entry : jobject.entrySet()) { 
      Field field = searchField(entry.getKey().toString()); 
      if (field != null) { 
       field.setAccessible(true); 
       try { 
        Object r = converterForClass.get(field.getType()).convert(entry.getValue().toString()); 
        field.set(foo, r); 
       } catch (IllegalAccessException e) { 
        e.printStackTrace(); 
       } 
      } 
     } 
     return foo; 

    } 

    private Field searchField(String name) { 
     Field[] fields = Foo.class.getDeclaredFields(); 

     for (Field field : fields) { 
      field.setAccessible(true); 
      if (field.isAnnotationPresent(SerializedName.class)) { 
       String value = field.getAnnotation(SerializedName.class).value(); 

       Matcher matcher = PATTERN.matcher(value); 
       if (value.equals(name)) { 
        return field; 
       } else if (matcher.find()) { 
        if (props.get(matcher.group(1)).equals(name)) { 
         return field; 
        } 
       } 
      } else { 
       if (field.getName().equals(name)) { 
        return field; 
       } 
      } 
     } 

     return null; 
    } 

デシリアライザを登録します。

gsonBuilder.registerTypeAdapter(Foo.class, new FooDeserializer()); 

を上記のアプローチの問題は、それがネストされたオブジェクトでは動作しませんです。それ以上の検証と実装が必要です。これはJava 8の機能も使用しています。

+0

デシリアライズと同じ方法で表示できますか? – bryce

+1

各タイプの問題があるため、直列化復元は少し難しくなります。私はそれを単純化する方法を少し考えなければならないでしょう。すぐに何かを載せてください。 – dambros

+0

私のアプリケーションでは、propertieファイルのいくつかのフィールドが必要です。他のフィールドはすべての環境を通して同じ名前を持つことになります。だから、正規表現は非常に良いアイデアです – bryce

関連する問題