2012-11-20 15 views
11

मैं जर्सी में क्वेरी पैरामीटर के लिए जोडा के DateTime का उपयोग करना चाहता हूं, लेकिन यह जर्सी द्वारा ऑफ़-द-बॉक्स द्वारा समर्थित नहीं है। मुझे लगता है कि InjectableProvider को लागू करना DateTime समर्थन जोड़ने का उचित तरीका है।जर्सी डेटटाइम का उपयोग जर्सी पैरामीटर के रूप में करना?

क्या कोई मुझे InjectableProvider के DateTime के लिए एक अच्छा कार्यान्वयन करने के लिए इंगित कर सकता है? या क्या सिफारिश करने के लायक एक वैकल्पिक दृष्टिकोण है? (मुझे पता है कि मैं अपने कोड में Date या String से परिवर्तित कर सकता हूं, लेकिन यह एक कम समाधान की तरह लगता है)।

धन्यवाद।

समाधान:

मैं नीचे जिली का जवाब Guice JAX-रुपये के बजाय में @Context इंजेक्शन प्रणाली का उपयोग करने के लिए संशोधित।

अद्यतन: यदि आपकी सेवा विधि पैरामीटर में UriInfo इंजेक्शन नहीं दिया गया है तो यह ठीक से काम नहीं कर सकता है।

import com.sun.jersey.core.spi.component.ComponentContext; 
import com.sun.jersey.spi.inject.Injectable; 
import com.sun.jersey.spi.inject.PerRequestTypeInjectableProvider; 
import java.util.List; 
import javax.ws.rs.QueryParam; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.Context; 
import javax.ws.rs.core.Response; 
import javax.ws.rs.core.Response.Status; 
import javax.ws.rs.core.UriInfo; 
import javax.ws.rs.ext.Provider; 
import org.joda.time.DateTime; 

/** 
* Enables DateTime to be used as a QueryParam. 
* <p/> 
* @author Gili Tzabari 
*/ 
@Provider 
public class DateTimeInjector extends PerRequestTypeInjectableProvider<QueryParam, DateTime> 
{ 
    private final UriInfo uriInfo; 

    /** 
    * Creates a new DateTimeInjector. 
    * <p/> 
    * @param uriInfo an instance of {@link UriInfo} 
    */ 
    public DateTimeInjector(@Context UriInfo uriInfo) 
    { 
     super(DateTime.class); 
     this.uriInfo = uriInfo; 
    } 

    @Override 
    public Injectable<DateTime> getInjectable(final ComponentContext cc, final QueryParam a) 
    { 
     return new Injectable<DateTime>() 
     { 
      @Override 
      public DateTime getValue() 
      { 
       final List<String> values = uriInfo.getQueryParameters().get(a.value()); 

       if(values == null || values.isEmpty()) 
        return null; 
       if (values.size() > 1) 
       { 
        throw new WebApplicationException(Response.status(Status.BAD_REQUEST). 
         entity(a.value() + " may only contain a single value").build()); 
       } 
       return new DateTime(values.get(0)); 
      } 
     }; 
    } 
} 

उत्तर

5

यहां एक कार्यान्वयन है जो गुइस पर निर्भर करता है। आप मामूली संशोधनों के साथ एक अलग इंजेक्टर का उपयोग कर सकते हैं:

import com.google.inject.Inject; 
import com.sun.jersey.core.spi.component.ComponentContext; 
import com.sun.jersey.spi.inject.Injectable; 
import com.sun.jersey.spi.inject.PerRequestTypeInjectableProvider; 
import java.util.List; 
import javax.ws.rs.QueryParam; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.Response; 
import javax.ws.rs.core.Response.Status; 
import javax.ws.rs.core.UriInfo; 
import javax.ws.rs.ext.Provider; 
import org.joda.time.DateTime; 

/** 
* Enables DateTime to be used as a QueryParam. 
* <p/> 
* @author Gili Tzabari 
*/ 
@Provider 
public class DateTimeInjector extends PerRequestTypeInjectableProvider<QueryParam, DateTime> 
{ 
    private final com.google.inject.Provider<UriInfo> uriInfo; 

    /** 
    * Creates a new DateTimeInjector. 
    * <p/> 
    * @param uriInfo an instance of {@link UriInfo} 
    */ 
    @Inject 
    public DateTimeInjector(com.google.inject.Provider<UriInfo> uriInfo) 
    { 
     super(DateTime.class); 
     this.uriInfo = uriInfo; 
    } 

    @Override 
    public Injectable<DateTime> getInjectable(final ComponentContext cc, final QueryParam a) 
    { 
     return new Injectable<DateTime>() 
     { 
      @Override 
      public DateTime getValue() 
      { 
       final List<String> values = uriInfo.get().getQueryParameters().get(a.value()); 
       if (values.size() > 1) 
       { 
        throw new WebApplicationException(Response.status(Status.BAD_REQUEST). 
         entity(a.value() + " may only contain a single value").build()); 
       } 
       if (values.isEmpty()) 
        return null; 
       return new DateTime(values.get(0)); 
      } 
     }; 
    } 
} 

कोई गिवाइस बाइंडिंग नहीं है। @ प्रदाता एक जेएक्स-आरएस एनोटेशन है। गुइस को केवल UriInfo इंजेक्ट करने में सक्षम होना चाहिए और Jersey-Guice बाध्यकारी प्रदान करता है।

+0

धन्यवाद, गिली। मैं गुइस का उपयोग नहीं कर रहा हूं, लेकिन मुझे आश्चर्य है कि क्या UriInfo को JAX-RS के @Context इंजेक्शन से इंजेक्शन दिया जा सकता है? – HolySamosa

+0

हाँ, @Context UriInfo इंजेक्शन के लिए काम करता है। मैंने शून्य कोडटाइम क्वेरी पैरामीटर के मामले को संभालने के लिए थोड़ा सा कोड भी संशोधित किया है। मेरा अनुकूलन मेरे प्रश्न के संपादन के रूप में पोस्ट किया गया है। धन्यवाद!! – HolySamosa

1

the documentation पढ़ने से, यह जाहिर होता है कि आप अपने विधि एक स्ट्रिंग है जिसे आप दिनांक समय में बदल जाते हैं लौटने की आवश्यकता होगी, मैं DateTime(long) constructor का उपयोग कर लगता है, वहाँ एक (अपेक्षाकृत) में आसान है example at codehale का पालन करें, मुझे बताएं कि क्या आप मुझे इसमें जाना चाहते हैं।

1

@ जिली, खेद मैं आवश्यक प्रतिष्ठा सीधे अपनी पोस्ट टिप्पणी करने की जरूरत नहीं है, लेकिन आप कृपया सकता है:

  • आयात अपने कार्यान्वयन के लिए इस्तेमाल किया बयान जोड़ सकता हूँ?
  • एक उदाहरण जोड़ें कि आप गुइस के साथ सबकुछ कैसे बांधते हैं?

आपको बहुत पहले धन्यवाद।

एम


समस्याओं:

मैं HolySamosa के रूप में ही करने में रुचि हो सकता है, और मैं भी Guice का उपयोग करें, लेकिन मैं नीचे मुद्दे का सामना।

अगर मैं जोड़ें:

bind(DateTimeInjector.class); 
मेरी GuiceServletContextListener में

, मैं मिलता है:

java.lang.RuntimeException: 
The scope of the component class com.foo.mapping.DateTimeInjector must be a singleton 

और अगर मैं DateTimeInjector वर्ग पर @Singleton जोड़ने के लिए, मैं:

GRAVE: The following errors and warnings have been detected with resource and/or provider classes: 
SEVERE: Missing dependency for method public java.util.List com.foo.ThingService.getThingByIdAndDate(java.lang.String,org.joda.time.DateTime) at parameter at index 1 
SEVERE: Method, public java.util.List com.foo.ThingService.getThingByIdAndDate(java.lang.String,org.joda.time.DateTime), annotated with GET of resource, class com.foo.ThingService, is not recognized as valid resource method. 

सलाह/समाधान:

  • क्या एनोटेशन आप उपयोग करना वेतन ध्यान (मुझे के विपरीत)! उदाहरण के लिए मैं वास्तव में @QueryParam के बजाय @PathParam का उपयोग कर रहा था।
  • आपकी सेवा में, आपको विधि के हस्ताक्षर में UriInfo uriInfo होने की आवश्यकता नहीं है। बस कार्यात्मक पैरामीटर पर्याप्त होना चाहिए और यह काम करना चाहिए कि UriInfo मौजूद है या नहीं।
  • इंजेक्टर लेने में सक्षम होने के लिए नीचे दिए गए गिइस को कॉन्फ़िगर करने की आवश्यकता है।

उदाहरण:

// Configure Jersey with Guice: 
Map<String, String> settings = new HashMap<String, String>(); 
settings.put(PackagesResourceConfig.PROPERTY_PACKAGES, "com.foo.mapping"); 
serve("/*").with(GuiceContainer.class, settings); 

पूर्ण समाधान:

import java.util.List; 

import javax.ws.rs.PathParam; 
import javax.ws.rs.WebApplicationException; 
import javax.ws.rs.core.Response; 
import javax.ws.rs.core.Response.Status; 
import javax.ws.rs.core.UriInfo; 
import javax.ws.rs.ext.Provider; 

import org.joda.time.DateTime; 

import com.google.inject.Inject; 
import com.foo.utils.DateTimeAdapter; 
import com.sun.jersey.core.spi.component.ComponentContext; 
import com.sun.jersey.spi.inject.Injectable; 
import com.sun.jersey.spi.inject.PerRequestTypeInjectableProvider; 

/** 
* Enables DateTime to be used as a PathParam. 
*/ 
@Provider 
public class DateTimeInjector extends PerRequestTypeInjectableProvider<PathParam, DateTime> { 
    private final com.google.inject.Provider<UriInfo> uriInfo; 

    /** 
    * Creates a new DateTimeInjector. 
    * 
    * @param uriInfo 
    *   an instance of {@link UriInfo} 
    */ 
    @Inject 
    public DateTimeInjector(com.google.inject.Provider<UriInfo> uriInfo) { 
     super(DateTime.class); 
     this.uriInfo = uriInfo; 
    } 

    @Override 
    public Injectable<DateTime> getInjectable(final ComponentContext context, final PathParam annotation) { 
     return new Injectable<DateTime>() { 
      @Override 
      public DateTime getValue() { 
       final List<String> values = uriInfo.get().getPathParameters().get(annotation.value()); 

       if (values == null) { 
        throwInternalServerError(annotation); 
       } 

       if (values.size() > 1) { 
        throwBadRequestTooManyValues(annotation); 
       } 

       if (values.isEmpty()) { 
        throwBadRequestMissingValue(annotation); 
       } 

       return parseDate(annotation, values); 
      } 

      private void throwInternalServerError(final PathParam annotation) { 
       String errorMessage = String.format("Failed to extract parameter [%s] using [%s]. This is likely to be an implementation error.", 
         annotation.value(), annotation.annotationType().getName()); 
       throw new WebApplicationException(Response.status(Status.INTERNAL_SERVER_ERROR).entity(errorMessage).build()); 
      } 

      private void throwBadRequestTooManyValues(final PathParam annotation) { 
       String errorMessage = String.format("Parameter [%s] must only contain one single value.", annotation.value()); 
       throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(errorMessage).build()); 
      } 

      private void throwBadRequestMissingValue(final PathParam annotation) { 
       String errorMessage = String.format("Parameter [%s] must be provided.", annotation.value()); 
       throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(errorMessage).build()); 
      } 

      private DateTime parseDate(final PathParam annotation, final List<String> values) { 
       try { 
        return DateTimeAdapter.parse(values.get(0)); 
       } catch (Exception e) { 
        String errorMessage = String.format("Parameter [%s] is formatted incorrectly: %s", annotation.value(), e.getMessage()); 
        throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity(errorMessage).build()); 
       } 
      } 

     }; 
    } 
} 
+0

मैंने अपना जवाब अपडेट कर लिया है। – Gili

+0

@Marc: प्रश्न में मेरे संपादन में गैर-गिस संस्करण देखें। – HolySamosa

+0

@ होलीसामोसा: गुइस के बिना '@ संदर्भ 'का उपयोग करना प्रतीत नहीं होता है अगर आप अपनी सेवा के पैरामीटर पैरामीटर में' UriInfo uriInfo' प्रदान नहीं करते हैं। क्या आपके पास केवल डेटटाइम पैरामीटर, या कुछ अन्य जर्सी विशिष्ट पैरामीटर भी हैं? जैसे 'सार्वजनिक शून्य बचत संसाधन (@Context UriInfo uriInfo, @QueryParam (" date ") दिनांक समय दिनांक) {...}' या आप कुछ अन्य "चाल" का उपयोग करते हैं? –

2

साथ Joda दिनांक समय भेजने क्लाइंट-सर्वर के बीच वस्तुओं निपटने के लिए एक अन्य विकल्प मार्शल करने के लिए है/डी-मार्शल उन्हें स्पष्ट रूप से एक एडाप्टर और एक एनोटेशन का उपयोग कर। सिद्धांत यह है कि इसे लंबे ऑब्जेक्ट के रूप में मार्शल करना है जबकि डी-मार्शलिंग ने कन्स्ट्रक्टर कॉल के लिए लंबी ऑब्जेक्ट का उपयोग करके एक नई डेटटाइम ऑब्जेक्ट को तुरंत चालू किया है। लांग ऑब्जेक्ट getMillis विधि के माध्यम से प्राप्त किया जाता है। इस काम करवाने के लिए, अनुकूलक वर्गों दिनांक समय वस्तु है कि में उपयोग करने के लिए निर्दिष्ट करें:

import javax.xml.bind.annotation.adapters.XmlAdapter; 
import org.joda.time.DateTime; 
import org.joda.time.DateTimeZone; 

/** 
* Convert between joda datetime and XML-serialisable millis represented as long 
*/ 
public class XmlDateTimeAdapter extends XmlAdapter<XmlDateTime, DateTime> { 

    @Override 
    public XmlDateTime marshal(DateTime v) throws Exception { 

     if(v != null) 
      return new XmlDateTime(v.getMillis()); 
     else 
      return new XmlDateTime(0); 


    } 

    @Override 
    public DateTime unmarshal(XmlDateTime v) throws Exception { 

     return new DateTime(v.millis, DateTimeZone.UTC); 
    } 
} 


import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

/** 
* XML-serialisable wrapper for joda datetime values. 
*/ 
@XmlRootElement(name="joda_datetime") 
public class XmlDateTime { 

    @XmlElement(name="millis") public long millis; 

    public XmlDateTime() {}; 

    public XmlDateTime(long millis) { this.millis = millis; } 

} 

सब हैं:

@XmlElement(name="capture_date") 
@XmlJavaTypeAdapter(XmlDateTimeAdapter.class) 
public DateTime getCaptureDate() { return this.capture_date; } 
public void setCaptureDate(DateTime capture_date) { this.capture_date = capture_date; } 

फिर लांग वस्तु संपुटित करने के लिए एडाप्टर और एक्सएमएल वर्ग बारे में योजना में जाता है, डेटटाइम ऑब्जेक्ट्स एडाप्टर का उपयोग करके marshalled/de-marshalled किया जाना चाहिए; एडाप्टर में ब्रेकपॉइंट्स सेट करके इसे जांचें।

संबंधित मुद्दे