मैं वर्तमान में जर्सी के साथ InjectableProvider
बनाने की कोशिश कर रहा हूं, लेकिन मुझे जर्सी इसे लेने के लिए नहीं मिल सकता है।जर्सी: इंजेक्शन योग्य प्रदाता नहीं उठाया गया - वसंत
कार्यान्वयन पर @Provider
एनोटेशन का उपयोग करने के अलावा मुझे इसके उपयोग के किसी भी वास्तविक उदाहरण नहीं मिलते हैं, या यहां तक कि इसे कैसे उठाया जा सकता है। जिस व्यक्ति ने इसे जर्सी के भीतर लिखा है वह कुछ पदों में उल्लिखित है कि यह इसे उठाए जाने के लिए पर्याप्त है।
क्या मुझे कुछ एसपीआई सेवा फ़ाइल निर्दिष्ट करने की आवश्यकता है, या इसे कहीं किसी कारखाने में जोड़ना है?
नोट: मैं ग्लासफ़िश 3.1 के भीतर चल रहा हूं, और स्प्रिंग 3.1 का उपयोग कर रहा हूं। ऐसा लगता है कि वसंत Provider
एस की स्वचालित लोडिंग के लिए किसी भी तरह से हो सकता है। हालांकि, मैं बस नहीं जानता। मैं नीचे दिए गए इंजेक्शन योग्य प्रदाता को प्रबंधित करने के लिए वैसे भी वसंत का उपयोग नहीं कर रहा हूं, न ही मैं इसे किसी अन्य तरीके से जोड़ने की कोशिश कर रहा हूं, जो मेरी समस्या हो सकती है।
import com.sun.jersey.core.spi.component.ComponentContext;
import com.sun.jersey.spi.inject.Injectable;
import com.sun.jersey.spi.inject.PerRequestTypeInjectableProvider;
public abstract class AbstractAttributeInjectableProvider<T>
extends PerRequestTypeInjectableProvider<AttributeParam, T>
{
protected final Class<T> type;
public AbstractAttributeInjectableProvider(Class<T> type)
{
super(type);
this.type = type;
}
@Override
public Injectable<T> getInjectable(ComponentContext componentContext,
AttributeParam attributeParam)
{
return new AttributeInjectable<T>(type, attributeParam.value());
}
}
बेसिक कार्यान्वयन:
import javax.ws.rs.ext.Provider;
@Component // <- Spring Annotation
@Provider // <- Jersey Annotation
public class MyTypeAttributeInjectableProvider
extends AbstractAttributeInjectableProvider<MyType>
{
public MyTypeAttributeInjectableProvider()
{
super(MyType.class);
}
}
संदर्भ Annotation
:
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface AttributeParam
{
/**
* The value is the name to request as an attribute from an {@link
* HttpContext}'s {@link HttpServletRequest}.
* @return Never {@code null}. Should never be blank.
*/
String value();
}
संदर्भ link from Jersey developer।
अद्यतन: calvinkrishy मेरी सोच के लिए दो खामियों ने बताया।
सबसे पहले, मुझे लगता है कि जर्सी पारंपरिक जर्सी-स्प्रिंग सर्वलेट द्वारा लात मारने के बाद @Provider
के लिए स्कैनिंग करने जा रहा था: com.sun.jersey.spi.spring.container.servlet.SpringServlet
। यह ज्यादातर गलत था; यह स्कैनिंग शुरू करता है, लेकिन यह वसंत बीन्स की तलाश करता है जिसमें एनोटेशन होता है।
दूसरा, मुझे लगता है कि PerRequestTypeInjectableProvider
को Injectable
के प्रत्येक इनकमिंग अनुरोध पर उस एनोटेशन को नियंत्रित करने के लिए कहा जाएगा जो इसे नियंत्रित करता है। यह भी गलत था। PerRequestTypeInjectableProvider
को अपेक्षित के रूप में स्टार्टअप पर तुरंत चालू किया गया है, लेकिन जर्सी तत्काल को type
के साथ दिए गए एनोटेशन को संभालने के लिए तत्काल पूछताछ करता है, जो यह उस विश्वसनीय सेवाओं को स्कैन करके निर्धारित करता है - इस बिंदु पर - यह तय किया गया कि यह प्रबंधन (जो कहने के लिए, उन सभी को)।
PerRequestTypeInjectableProvider
और SingletonTypeInjectableProvider
के बीच का अंतर हो रहा है कि जिसके परिणामस्वरूप Injectable
या तो इसे (सिंगलटन) के लिए काम के बिना मूल्य होता है, या यह इसे हर बार मूल्य के लिए (अनुरोध के अनुसार) लग रहा है, इस प्रकार के लिए मूल्य को सक्षम करने प्रति अनुरोध बदलें।
यह मैं मजबूर कर नहीं बल्कि कुछ वस्तुओं में से गुजर रहा, जैसा कि मैंने योजना बनाई थी, AttributeInjectable
अतिरिक्त ज्ञान देने से बचने के लिए की तुलना में मेरी AttributeInjectable
(नीचे दिए गए कोड) में कुछ अतिरिक्त काम करने के लिए से मेरी योजनाओं में एक छोटे रिंच फेंक दिया।
public class AttributeInjectable<T> implements Injectable<T>
{
/**
* The type of data that is being requested.
*/
private final Class<T> type;
/**
* The name to extract from the {@link HttpServletRequest} attributes.
*/
private final String name;
/**
* Converts the attribute with the given {@code name} into the {@code type}.
* @param type The type of data being retrieved
* @param name The name being retrieved.
* @throws IllegalArgumentException if any parameter is {@code null}.
*/
public AttributeInjectable(Class<T> type, String name)
{
// check for null
// required
this.type = type;
this.name = name;
}
/**
* Look up the requested value.
* @return {@code null} if the attribute does not exist or if it is not the
* appropriate {@link Class type}.
* <p />
* Note: Jersey most likely will fail if the value is {@code null}.
* @throws NullPointerException if {@link HttpServletRequest} is unset.
* @see #getRequest()
*/
@Override
public T getValue()
{
T value = null;
Object object = getRequest().getAttribute(name);
if (type.isInstance(object))
{
value = type.cast(object);
}
return value;
}
/**
* Get the current {@link HttpServletRequest} [hopefully] being made
* containing the {@link HttpServletRequest#getAttribute(String) attribute}.
* @throws NullPointerException if the Servlet Filter for the {@link
* RequestContextHolder} is not setup
* appropriately.
* @see org.springframework.web.filter.RequestContextFilter
*/
protected HttpServletRequest getRequest()
{
// get the request from the Spring Context Holder (this is done for
// every request by a filter)
ServletRequestAttributes attributes =
(ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
return attributes.getRequest();
}
}
मैं Provider
से HttpServletRequest
में पारित करने के लिए सक्षम होने के लिए उम्मीद कर रहा था, लेकिन AttributeInjectable
केवल प्रति अद्वितीय एनोटेशन/प्रकार instantiated है। जैसा कि मैं ऐसा नहीं कर सकता, मैं प्रति मान लुकअप करता हूं, जो स्प्रिंग के RequestContextFilter
सिंगलटन का उपयोग करता है, जो ThreadLocal
तंत्र को HttpServletRequest
(वर्तमान अनुरोध से संबंधित अन्य चीज़ों के बीच) को सुरक्षित रूप से पुनर्प्राप्त करने के लिए प्रदान करता है।
<filter>
<filter-name>requestContextFilter</filter-name>
<filter-class>
org.springframework.web.filter.RequestContextFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>requestContextFilter</filter-name>
<url-pattern>/path/that/i/wanted/*</url-pattern>
</filter-mapping>
परिणाम काम करता है, और यह सिर्फ @Context HttpServletRequest request
के उपयोग, जो तब गुण का उपयोग करने के रूप में कुछ के माध्यम से ऊपर किया प्रयोग किया जाता है को छिपाने के लिए एक आधार वर्ग का विस्तार करने के विभिन्न सेवाओं के लिए मजबूर कर के बिना बहुत अधिक पठनीय कोड बनाता है सहायक विधि।
तो फिर तुम इस की तर्ज पर कुछ कर सकते हैं:
@Path("my/path/to")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
public interface MyService
{
@Path("service1")
@POST
Response postData(@AttributeParam("some.name") MyType data);
@Path("service2")
@POST
Response postOtherData(@AttributeParam("other.name") MyOtherType data);
}
@Component // Spring
public class MyServiceBean implements MyService
{
@Override
public Response postData(MyType data)
{
// interact with data
}
@Override
public Response postOtherData(MyOtherType data)
{
// interact with data
}
}
यह बहुत सुविधाजनक के रूप में मैं एक सर्वलेट फ़िल्टर का उपयोग उपयोगकर्ता डेटा पार करने से पहले सेवा का उपयोग करने के लिए उचित विशेषाधिकार नहीं होता है कि यह सुनिश्चित करने के बन जाता है, और फिर मैं आने वाले डेटा को पार्स कर सकता हूं (या इसे लोड कर सकता हूं, या जो भी हो) और इसे लोड करने के लिए विशेषता में डंप कर सकता हूं।
आप ऊपर Provider
दृष्टिकोण नहीं करना चाहते हैं, और आप गुण तक पहुँचने के लिए आधार वर्ग चाहते हैं, तो यहाँ तुम जाओ:
public class RequestContextBean
{
/**
* The current request from the user.
*/
@Context
protected HttpServletRequest request;
/**
* Get the attribute associated with the current {@link HttpServletRequest}.
* @param name The attribute name.
* @param type The expected type of the attribute.
* @return {@code null} if the attribute does not exist, or if it does not
* match the {@code type}. Otherwise the appropriately casted
* attribute.
* @throws NullPointerException if {@code type} is {@code null}.
*/
public <T> T getAttribute(String name, Class<T> type)
{
T value = null;
Object attribute = request.getAttribute(name);
if (type.isInstance(attribute))
{
value = type.cast(attribute);
}
return value;
}
}
@Path("my/path/to")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.TEXT_PLAIN)
public interface MyService
{
@Path("service1")
@POST
Response postData();
@Path("service2")
@POST
Response postOtherData();
}
@Component
public class MyServiceBean extends RequestContextBean implements MyService
{
@Override
public Response postData()
{
MyType data = getAttribute("some.name", MyType.class);
// interact with data
}
@Override
Response postOtherData()
{
MyOtherType data = getAttribute("other.name", MyOtherType.class);
// interact with data
}
}
UPDATE2: मैं अपने कार्यान्वयन के बारे में सोचा AbstractAttributeInjectableProvider
, जो स्वयं ही एक सामान्य वर्ग है जो AttributeInjectable
के किसी दिए गए प्रकार, Class<T>
और आपूर्ति AttributeParam
प्रदान करने के लिए मौजूद है। गैर-abstract
कार्यान्वयन प्रदान करना कहीं अधिक आसान है जिसे प्रत्येक प्रकार AttributeParam
के साथ अपने प्रकार (Class<T>
) बताया गया है, इस प्रकार आपके लिए प्रकार प्रदान करने वाले केवल कन्स्ट्रक्टर-केवल कार्यान्वयन का एक समूह से बचें। यह AttributeParam
एनोटेशन के साथ उपयोग करने के लिए हर एक प्रकार के लिए कोड लिखने से बचाता है।
@Component
@Provider
public class AttributeParamInjectableProvider
implements InjectableProvider<AttributeParam, Type>
{
/**
* {@inheritDoc}
* @return Always {@link ComponentScope#PerRequest}.
*/
@Override
public ComponentScope getScope()
{
return ComponentScope.PerRequest;
}
/**
* Get an {@link AttributeInjectable} to inject the {@code parameter} for
* the given {@code type}.
* @param context Unused.
* @param parameter The requested parameter
* @param type The type of data to be returned.
* @return {@code null} if {@code type} is not a {@link Class}. Otherwise
* an {@link AttributeInjectable}.
*/
@Override
public AttributeInjectable<?> getInjectable(ComponentContext context,
AttributeParam parameter,
Type type)
{
AttributeInjectable<?> injectable = null;
// as long as it's something that we can work with...
if (type instanceof Class)
{
injectable = getInjectable((Class<?>)type, parameter);
}
return injectable;
}
/**
* Create a new {@link AttributeInjectable} for the given {@code type} and
* {@code parameter}.
* <p />
* This is provided to avoid the support for generics without the need for
* {@code SuppressWarnings} (avoided via indirection).
* @param type The type of data to be returned.
* @param parameter The requested parameter
* @param <T> The type of data being accessed by the {@code param}.
* @return Never {@code null}.
*/
protected <T> AttributeInjectable<T> getInjectable(Class<T> type,
AttributeParam parameter)
{
return new AttributeInjectable<T>(type, parameter.value());
}
}
नोट: प्रत्येक Injectable
स्टार्टअप पर बजाय अनुरोध के अनुसार एक बार instantiated है, लेकिन वे प्रत्येक आवक अनुरोध पर लागू कर रहे हैं।
प्रदाता को बीन्स के रूप में स्थापित करना (या उन्हें स्वचालित रूप से उठाया जाना) उन्हें लगता है कि उन्हें उठाया जाता है, लेकिन मुझे कुछ कारणों से उन्हें सिंगलेट बनाने के लिए मजबूर होना पड़ता है। क्या आपको कोई विचार है कि मुझे 'PerRequestTypeInjectableProvider' सिंगलटन को स्कॉप्ड करने की आवश्यकता क्यों है? अगर मैं इसे अनुरोध के दायरे में मजबूर करता हूं, तो यह अपवाद के साथ विफल रहता है। उदाहरण वास्तव में मूल इंजेक्शन योग्य प्रदाता उदाहरण था जिसने मुझे इस पर पहुंचाया। वह कोड उदाहरण जो वह प्रदान करता है वह सर्वश्रेष्ठ नहीं है (वह 'प्रक्षेपक' को 'इंजेक्शन योग्य' के साथ जोड़ता है)। यह बेवकूफ है कि जर्सी ने 'ServletRequest' को दूर करने की कोशिश की। – pickypg
अधिक जानकारी के साथ अपडेट किया गया। संक्षेप में, 'प्रदाता' एक सिंगलटन होने की सुविधा है लेकिन प्रत्येक अनुरोध के लिए एक नया मूल्य प्रदान किया जाना चाहिए। – calvinkrishy
आह हे। मैं 'PerRequestTypeInjectableProvider' के उद्देश्य को गलत समझ रहा था। जर्सी तुरंत इंजेक्शन योग्य बनाता है कि यह तय करता है कि इसे नियंत्रित करने वाली विभिन्न आवश्यक सेवाओं को स्कैन करने के बाद इसकी आवश्यकता है। मैंने "PerRequest" का अर्थ यह लिया कि प्रत्येक प्रदाता के साथ 'प्रदाता' की जांच की जाएगी। मैं 'एट्रिब्यूटरम' को दिए गए नाम के साथ 'HttpServletRequest # getAttribute (स्ट्रिंग)' निकालने के लिए 'HttpServletRequest' को 'HttpServletRequest' इंजेक्ट करने के लिए' प्रदाता 'का उपयोग करना चाहता था। इस तरह मेरी सशक्त सेवाओं में गुणों को इंजेक्शन दिया जा सकता है। – pickypg