如何让Gson使用访问器而不是字段?

默认情况下,Gson使用字段作为序列化的基础。 有没有办法让它改为使用访问器?

Gson的开发人员表示 ,他们从未对添加此function的请求感到不满,他们担心会滥用api来增加对此的支持。

添加此function的一种方法是使用TypeAdapter(我为粗糙的代码道歉,但这certificate了原理):

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 extends TypeAdapter { 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注册 – 可能检查是否存在运行时注释:

 public class TypeFactory implements TypeAdapterFactory { @SuppressWarnings("unchecked") public  TypeAdapter create(final Gson gson, final TypeToken type) { Class t = type.getRawType(); if(t.isAnnotationPresent(UseAccessor.class)) { return (TypeAdapter) new AccessorBasedTypeAdaptor(gson); } return null; } 

创建gson实例时,可以将其指定为正常:

 new GsonBuilder().registerTypeAdapterFactory(new TypeFactory()).create(); 

注意:我是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

要将MOXy配置为JAXB提供程序,您需要在与域模型相同的程序包中添加名为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 properties = new HashMap(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" } } 

了解更多信息