2012-07-08 29 views

Trả lời

7

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(); 
+0

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(). –

+0

@ plasma147 Cảm ơn vì điều này! Đây là chú thích UseAccessor: '@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.TYPE) public @interface UseAccessor { }' –

+0

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

2

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

Các vấn đề liên quan