デフォルトでは、Gsonはシリアル化のためのフィールドとしてフィールドを使用します。代わりにアクセサーを使用する方法がありますか?Gsonにフィールドではなくアクセサーを使用させるにはどうすればよいですか?
答えて
Gson sayの開発者は、この機能を追加する要求に揺さぶられたことは決してありませんでした。また、これをサポートするためにAPIを怪しくすることを心配していました。この機能を追加する
一つの方法は、(私は危ないコードをお詫び申し上げますが、これは原理を実証)TypeAdapterを使用することです:
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import com.google.common.base.CaseFormat;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
public class AccessorBasedTypeAdaptor<T> extends TypeAdapter<T> {
private Gson gson;
public AccessorBasedTypeAdaptor(Gson gson) {
this.gson = gson;
}
@SuppressWarnings("unchecked")
@Override
public void write(JsonWriter out, T value) throws IOException {
out.beginObject();
for (Method method : value.getClass().getMethods()) {
boolean nonBooleanAccessor = method.getName().startsWith("get");
boolean booleanAccessor = method.getName().startsWith("is");
if ((nonBooleanAccessor || booleanAccessor) && !method.getName().equals("getClass") && method.getParameterTypes().length == 0) {
try {
String name = method.getName().substring(nonBooleanAccessor ? 3 : 2);
name = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL, name);
Object returnValue = method.invoke(value);
if(returnValue != null) {
TypeToken<?> token = TypeToken.get(returnValue.getClass());
TypeAdapter adapter = gson.getAdapter(token);
out.name(name);
adapter.write(out, returnValue);
}
} catch (Exception e) {
throw new ConfigurationException("problem writing json: ", e);
}
}
}
out.endObject();
}
@Override
public T read(JsonReader in) throws IOException {
throw new UnsupportedOperationException("Only supports writes.");
}
}
あなたは指定された型のノーマルタイプのアダプタとしてこれを登録することができますかTypeAdapterfactoryて - おそらくランタイム注釈の存在をチェック:あなたのgsonインスタンスを作成する際に
public class TypeFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {
Class<? super T> t = type.getRawType();
if(t.isAnnotationPresent(UseAccessor.class)) {
return (TypeAdapter<T>) new AccessorBasedTypeAdaptor(gson);
}
return null;
}
これは通常のように指定することができます。
new GsonBuilder().registerTypeAdapterFactory(new TypeFactory()).create();
華麗な例。実際にこれを進めるなら、おそらくTypeAdapterFactory.create()のメソッドを探してキャッシュすることで、少し効率的にすることができます。 –
@ plasma147ありがとう! UseAccessorアノテーションは次のとおりです。 '@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface UseAccessor { } –
ありがとうございました!神様が私にこれ以上のトラブルをもたらしました。あなたが書いたものの正式な例がないのはなぜですか? UseAccessor-annotationのSmokyに感謝します。Javaにはかなり新しいので、注釈部分を理解しようとするとさらに問題が発生します。 – Whyser
注:私はEclipseLink JAXB (MOXy)リードとJAXB (JSR-222)専門家グループのメンバーです。
Gsonに必要な操作をさせることができない場合は、MOXyのネイティブJSONバインディングを使用してこれを実行する方法を以下に示します。 JAXB実装のようなMOXyは、デフォルトでプロパティ(パブリック)アクセスを使用します。 @XmlAccessorType(XmlAccessType.FIELD)
を使用してフィールドアクセスを設定できます。以下は例です:
カスタマー
package forum11385214;
public class Customer {
private String foo;
private Address bar;
public String getName() {
return foo;
}
public void setName(String name) {
this.foo = name;
}
public Address getAddress() {
return bar;
}
public void setAddress(Address address) {
this.bar = address;
}
}
住所
package forum11385214;
public class Address {
private String foo;
public String getStreet() {
return foo;
}
public void setStreet(String street) {
this.foo = street;
}
}
jaxb.properties
あなたのJAXBプロバイダとしてMOXYを設定するには、追加する必要がありますファイルjaxb.properties
をドメインモデルと同じパッケージに入れ、次のエントリを入力します(http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.htmlを参照)。詳細情報
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
デモ
package forum11385214;
import java.util.*;
import javax.xml.bind.*;
import javax.xml.transform.stream.StreamSource;
import org.eclipse.persistence.jaxb.JAXBContextProperties;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(2);
properties.put(JAXBContextProperties.MEDIA_TYPE, "application/json");
properties.put(JAXBContextProperties.JSON_INCLUDE_ROOT, false);
JAXBContext jc = JAXBContext.newInstance(new Class[] {Customer.class}, properties);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource json = new StreamSource("src/forum11385214/input.json");
Customer customer = (Customer) unmarshaller.unmarshal(json, Customer.class).getValue();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(customer, System.out);
}
}
input.json /出力
{
"name" : "Jane Doe",
"address" : {
"street" : "1 Any Street"
}
}
- 1. DataGridViewでバインドされていないフィールドを使用するにはどうすればよいですか?
- 2. SpringにTomcatではなくWildFlyを使用させるにはどうすればいいですか?
- 3. GsonでGeoJsonを解析するにはどうすればよいですか?
- 4. メソッド(.NET)で使用されるフィールドを取得するにはどうすればよいですか?
- 5. JackRabbitでSimpleSecurityManagerが使用されないようにするにはどうすればよいですか?
- 6. RetroFitでGsonコンバータを使用するにはどうすればよいですか?
- 7. 異なる列フィールドにオートコンプリートjQueryを使用するにはどうすればよいですか?テキストボックスフィールドで
- 8. フィールド内メソッドを使用するにはどうすればいいですか?
- 9. Gsonでフィールド名を設定するにはどうすればいいですか?
- 10. メインスレッドではなくワーカースレッドでAsyncSocketを使用するにはどうすればよいですか?
- 11. snabbdom-jsx(Reactではなく)でtsxを使用するにはどうすればよいですか?
- 12. 文字列ではなく、オブジェクトでGtkComboBoxを使用するにはどうすればよいですか?
- 13. Java ConcurrentNavigableMapをTreeMapではなくComparatorで使用するにはどうすればよいですか?
- 14. SASS構文(SCSSではなく)でサスマップを使用するにはどうすればよいですか?
- 15. 注釈を使用しないJacksonのフィールドを除外するにはどうすればよいですか?
- 16. Retrofit2、RxJava2、Gson TypeAdapterFActoryを使用してGsonを正しくマップするにはどうすればよいですか?
- 17. サーバータグで強く型付けされたリソースを使用するにはどうすればよいですか?
- 18. クエリではなくカウントを使用するにはどうすればよいですか?
- 19. Gsonでは、JsonObjectにJsonArrayを追加するにはどうすればよいですか?
- 20. Java ClassLoaderに使用可能なクラスを認識させるにはどうすればよいですか?
- 21. 登録されていないフィルタでプロパティページを使用するにはどうすればよいですか?
- 22. Hibernateによって生成されたユニークなフィールドを扱うにはどうすればいいですか?
- 23. GSONを使用してJSON応答を解析するにはどうすればいいですか
- 24. 基本的なJSONオブジェクトを解析するときにGSONがnullを返さないようにするにはどうすればよいですか?
- 25. dangerouslySetInnerHTMLを使用せずにReactでSVGを使用するにはどうすればよいですか?
- 26. ストーリーボードを使用せずにiOS 5でマルチビューアプリケーションを使用するにはどうすればよいですか?
- 27. 〜/ .irbrcファイルを使用せずにawesome_printを動作させるにはどうすればよいですか?
- 28. Collectionsクラスメソッドを使用せずにJavaコレクションクラスを同期させるにはどうすればよいですか?
- 29. デリゲートタイプに情報を保持させないようにするにはどうすればよいですか?
- 30. node.jsでモジュールを使用しないようにするにはどうすればよいですか?
?これは、非常に一般的な使用例をカバーしています。 – plasma147