2012-07-08 18 views
10

डिफ़ॉल्ट रूप से जीसन फ़ील्ड को इसके क्रमबद्धरण के आधार के रूप में उपयोग करता है। इसके बजाय एक्सेसर्स का उपयोग करने का कोई तरीका है?मैं जीसन को फ़ील्ड के बजाय एक्सेसर्स का उपयोग कैसे कर सकता हूं?

+2

कैसे है यह, अस्पष्ट अस्पष्ट, अधूरा, व्यापक, या बयानबाजी? इसमें एक बहुत ही सामान्य उपयोग केस शामिल है। – plasma147

उत्तर

7

जीसन say के डेवलपर्स जिन्हें उन्होंने कभी भी इस सुविधा को जोड़ने के अनुरोधों से प्रभावित महसूस नहीं किया और वे इसके लिए समर्थन जोड़ने के लिए एपीआई को छेड़छाड़ करने के बारे में चिंतित थे।

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."); 
    } 
} 

आप या किसी दिए गए प्रकार के लिए एक सामान्य प्रकार एडाप्टर के रूप में इस रजिस्टर कर सकते हैं: इस कार्यक्षमता जोड़ने की

एक तरह से एक TypeAdapter (मैं ऐंठा हुआ कोड के लिए हमें खेद है, लेकिन इस सिद्धांत को दर्शाता है) का उपयोग कर रहा है

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 उदाहरण बनाकर:

- एक TypeAdapterfactory के माध्यम से संभवतः एक क्रम एनोटेशन की उपस्थिति के लिए जाँच
new GsonBuilder().registerTypeAdapterFactory(new TypeFactory()).create(); 
+0

शानदार उदाहरण।यदि आप वास्तव में इसके साथ आगे बढ़ते हैं तो आप शायद TypeAdapterFactory.create() में विधियों को देखकर और कैश करके थोड़ा अधिक कुशल बना सकते हैं। –

+0

@ प्लाज्मा 147 इसके लिए धन्यवाद! यहां उपयोगकर्ता एनोटेशन है: '@ रीटेंशन (RetentionPolicy.RUNTIME) @ लक्ष्य (ElementType.TYPE) सार्वजनिक @ इंटरफेस उपयोगकर्ता { }' –

+0

धन्यवाद! भगवान ने मुझे बहुत अधिक परेशानी बचाई। आपने जो लिखा है उसका कोई आधिकारिक उदाहरण क्यों नहीं है? और धन्यवाद एक्सेसर-एनोटेशन के लिए स्मोकी, जावा के लिए बहुत नया, इसलिए मुझे एनोटेशन-पार्ट को समझने की कोशिश करने में और भी समस्या उत्पन्न हुई। – Whyser

2

नोट: मैं EclipseLink JAXB (MOXy) नेतृत्व और JAXB (JSR-222) विशेषज्ञ समूह का सदस्य हूँ।

यदि आप जीसन को जो भी चाहते हैं उसे करने के लिए नहीं मिल पा रहे हैं, तो नीचे आप मोक्सी के मूल 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 प्रदाता के रूप में कॉन्फ़िगर करने के लिए एक जोड़ने की जरूरत फ़ाइलकहा जाता हैउसी प्रविष्टि में आपके डोमेन मॉडल के रूप में निम्न प्रविष्टि के साथ (देखें: 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" 
    } 
} 

अधिक जानकारी के लिए