Theo mặc định, Gson sử dụng các trường làm cơ sở cho việc tuần tự hóa. Có cách nào để sử dụng accessors thay thế không?Làm cách nào để Gson sử dụng các trình truy cập thay vì các trường?
Trả lời
Các nhà phát triển của Gson say rằng họ không bao giờ cảm thấy bị ảnh hưởng bởi các yêu cầu thêm tính năng này và họ lo lắng về việc làm mờ lên api để thêm hỗ trợ cho việc này.
Một cách để thêm chức năng này là bằng cách sử dụng một TypeAdapter (Tôi xin lỗi vì mã gnarly nhưng điều này chứng tỏ nguyên tắc):
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.");
}
}
Bạn có thể đăng ký này như một loại bộ chuyển đổi bình thường đối với một loại nhất định hoặc thông qua một TypeAdapterfactory - có thể kiểm tra sự hiện diện của một chú thích thời gian chạy:
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;
}
này có thể được quy định như bình thường khi tạo ra Ví dụ gson của bạn:
new GsonBuilder().registerTypeAdapterFactory(new TypeFactory()).create();
Ví dụ điển hình.Nếu bạn thực sự đi tiếp với điều này, bạn có thể làm cho nó hiệu quả hơn một chút bằng cách tra cứu và lưu trữ các phương thức trong TypeAdapterFactory.create(). –
@ plasma147 Cảm ơn vì điều này! Đây là chú thích UseAccessor: '@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.TYPE) public @interface UseAccessor { }' –
Cảm ơn bạn! Đức Chúa Trời đã cứu tôi nhiều rắc rối hơn nữa. Tại sao không có bất kỳ ví dụ chính thức nào về những gì bạn đã viết? Và cảm ơn Smoky cho chú thích UseAccessor, khá mới đối với Java vì vậy sẽ khiến tôi còn gặp nhiều vấn đề hơn khi cố gắng tìm ra phần chú thích. – Whyser
Lưu ý: Tôi là người lãnh đạo EclipseLink JAXB (MOXy) và là thành viên của nhóm chuyên gia JAXB (JSR-222).
Nếu bạn không thể khiến Gson thực hiện những gì bạn muốn, dưới đây là cách bạn có thể thực hiện việc này bằng cách sử dụng liên kết JSON gốc của MOXy. MOXy giống như bất kỳ triển khai JAXB nào sẽ sử dụng quyền truy cập thuộc tính (public) theo mặc định. Bạn có thể định cấu hình truy cập trường bằng cách sử dụng @XmlAccessorType(XmlAccessType.FIELD)
. Dưới đây là một ví dụ:
khách hàng
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;
}
}
Địa chỉ
package forum11385214;
public class Address {
private String foo;
public String getStreet() {
return foo;
}
public void setStreet(String street) {
this.foo = street;
}
}
jaxb.properties
Để cấu hình MOXY là nhà cung cấp JAXB của bạn, bạn cần phải thêm một tệp có tên jaxb.properties
trong cùng một gói với mô hình miền của bạn với mục nhập sau (xem: http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html).
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Demo
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/Output
{
"name" : "Jane Doe",
"address" : {
"street" : "1 Any Street"
}
}
Để biết thêm thông tin
- 1. Làm cách nào để sử dụng các tab thay vì dấu cách trong Aptana Studio?
- 2. Làm cách nào để phân tích cú pháp các trường JSON động bằng GSON?
- 3. IDL: Truy cập các trường struct sử dụng tên trường được lưu trữ trong các biến?
- 4. Làm thế nào để tải một tập tin pyYAML và truy cập nó bằng cách sử dụng các thuộc tính thay vì sử dụng ký pháp từ điển?
- 5. Làm cách nào để truy cập các tệp trên Heroku?
- 6. Làm cách nào để loại trừ các trường có Jackson không sử dụng chú thích?
- 7. Làm cách nào để truy cập các trường tiêu đề yêu cầu HTTP qua JavaScript?
- 8. Làm cách nào để sử dụng rpm để cập nhật/thay thế các tệp hiện có?
- 9. R: các giá trị trường truy cập
- 10. Sử dụng nl80211.h để quét các điểm truy cập
- 11. Truy cập các trường riêng tư
- 12. Làm cách nào để thay đổi thứ tự các trường?
- 13. Có cách nào để sử dụng DPI trong các truy vấn phương tiện css thay vì px
- 14. Làm cách nào để truy cập các biến môi trường trong tập lệnh Mong đợi?
- 15. Làm cách nào để truy cập tất cả các trường biểu mẫu trong Sinatra?
- 16. Sử dụng GLshort thay vì GLfloat cho các đỉnh
- 17. Làm cách nào để truy cập bộ nhớ của các quá trình khác?
- 18. Làm cách nào để truy cập bộ nhớ sử dụng theo chương trình qua JMX?
- 19. Truy cập các tập tin bằng cách sử dụng Phonegap
- 20. Làm thế nào để sử dụng CURL thay vì file_get_contents?
- 21. Làm thế nào để sử dụng các mẫu gạch dưới thay vì Jade trong Express?
- 22. Ember.js: Làm thế nào để truy cập vào các trường hợp xem lồng nhau
- 23. Làm cách nào để thay đổi quyền truy cập tệp?
- 24. Strange loại không phù hợp khi sử dụng truy cập thành viên thay vì vắt
- 25. Làm cách nào để theo dõi các quy trình truy cập một tệp cụ thể?
- 26. Sử dụng IObservable thay vì các sự kiện
- 27. Ok để cập nhật các đoạn thay vì tạo các phiên bản mới?
- 28. Làm thế nào để sử dụng getnameinfo thay vì gethostbyname?
- 29. MATLAB - đặt/truy cập vào các trường của cấu trúc?
- 30. Trình tải có nên được sử dụng để truy cập các dịch vụ web không?
như thế nào này mơ hồ, không rõ ràng, không đầy đủ, quá rộng, hoặc hùng biện? Nó bao gồm một trường hợp sử dụng rất phổ biến. – plasma147