默认情况下,Gson使用字段作为序列化的基础。有没有办法让它使用访问器?
答案 0 :(得分:7)
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注册 - 可能检查是否存在运行时注释:
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;
}
创建gson实例时可以正常指定:
new GsonBuilder().registerTypeAdapterFactory(new TypeFactory()).create();
答案 1 :(得分:2)
注意:我是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<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"
}
}
了解更多信息