आप एक कस्टम एनोटेशन बना सकते हैं। मैं इसे कैसे करना है इसके बारे में बहुत कुछ नहीं जाऊंगा, आप this post, या this post देख सकते हैं। असल में यह जर्सी के साथ सामान्य निर्भरता इंजेक्शन की तुलना में एक अलग बुनियादी ढांचे पर निर्भर करता है। आप जर्सी परियोजना से this package देख सकते हैं। यह वह जगह है जहां सभी इंजेक्शन प्रदाता रहते हैं जो @XxxParam
इंजेक्शन को संभालते हैं। यदि आप स्रोत कोड की जांच करते हैं, तो आप देखेंगे कि कार्यान्वयन काफी समान हैं। ऊपर दिए गए दो लिंक एक ही पैटर्न का पालन करते हैं, साथ ही नीचे दिए गए कोड का पालन करते हैं।
क्या मैं एक कस्टम एनोटेशन
@Target({ElementType.FIELD, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface VaryingParam {
String value();
@SuppressWarnings("AnnotationAsSuperInterface")
public static class Factory
extends AnnotationLiteral<VaryingParam> implements VaryingParam {
private final String value;
public static VaryingParam create(final String newValue) {
return new Factory(newValue);
}
public Factory(String newValue) {
this.value = newValue;
}
@Override
public String value() {
return this.value;
}
}
}
यह अजीब है कि मैं एक कारखाने यह बनाने के लिए लग सकता है बनाया गया था था, लेकिन यह नीचे दिए गए कोड के कार्यान्वयन, जहां मैं का मूल्य विभाजित के लिए आवश्यक था स्ट्रिंग, और प्रत्येक विभाजन मूल्य के लिए एक नया एनोटेशन उदाहरण बनाते हैं।
यहां ValueFactoryProvider
है (जो, यदि आपने उपर्युक्त लेखों में से कोई भी पढ़ा है, तो आप देखेंगे कि कस्टम विधि पैरामीटर इंजेक्शन के लिए आवश्यक है)। यह एक बड़ी कक्षा है, केवल इसलिए कि मैंने जर्सी परियोजना में देखे गए पैटर्न के बाद, सभी आवश्यक कक्षाओं को एक ही कक्षा में रखा है।
public class VaryingParamValueFactoryProvider extends AbstractValueFactoryProvider {
@Inject
public VaryingParamValueFactoryProvider(
final MultivaluedParameterExtractorProvider mpep,
final ServiceLocator locator) {
super(mpep, locator, Parameter.Source.UNKNOWN);
}
@Override
protected Factory<?> createValueFactory(final Parameter parameter) {
VaryingParam annotation = parameter.getAnnotation(VaryingParam.class);
if (annotation == null) {
return null;
}
String value = annotation.value();
if (value == null || value.length() == 0) {
return null;
}
String[] variations = value.split("\\s*\\|\\s*");
return new VaryingParamFactory(variations, parameter);
}
private static Parameter cloneParameter(final Parameter original, final String value) {
Annotation[] annotations = changeVaryingParam(original.getAnnotations(), value);
Parameter clone = Parameter.create(
original.getRawType(),
original.getRawType(),
true,
original.getRawType(),
original.getRawType(),
annotations);
return clone;
}
private static Annotation[] changeVaryingParam(final Annotation[] annos, final String value) {
for (int i = 0; i < annos.length; i++) {
if (annos[i] instanceof VaryingParam) {
annos[i] = VaryingParam.Factory.create(value);
break;
}
}
return annos;
}
private class VaryingParamFactory extends AbstractContainerRequestValueFactory<Object> {
private final String[] variations;
private final Parameter parameter;
private final boolean decode;
private final Class<?> paramType;
private final boolean isList;
private final boolean isSet;
VaryingParamFactory(final String[] variations, final Parameter parameter) {
this.variations = variations;
this.parameter = parameter;
this.decode = !parameter.isEncoded();
this.paramType = parameter.getRawType();
this.isList = paramType == List.class;
this.isSet = paramType == Set.class;
}
@Override
public Object provide() {
MultivaluedParameterExtractor<?> e = null;
try {
Object value = null;
MultivaluedMap<String, String> params
= getContainerRequest().getUriInfo().getQueryParameters(decode);
for (String variant : variations) {
e = get(cloneParameter(parameter, variant));
if (e == null) {
return null;
}
if (isList) {
List list = (List<?>) e.extract(params);
if (value == null) {
value = new ArrayList();
}
((List<?>) value).addAll(list);
} else if (isSet) {
Set set = (Set<?>) e.extract(params);
if (value == null) {
value = new HashSet();
}
((Set<?>) value).addAll(set);
} else {
value = e.extract(params);
if (value != null) {
return value;
}
}
}
return value;
} catch (ExtractorException ex) {
if (e == null) {
throw new ParamException.QueryParamException(ex.getCause(),
parameter.getSourceName(), parameter.getDefaultValue());
} else {
throw new ParamException.QueryParamException(ex.getCause(),
e.getName(), e.getDefaultValueString());
}
}
}
}
private static class Resolver extends ParamInjectionResolver<VaryingParam> {
public Resolver() {
super(VaryingParamValueFactoryProvider.class);
}
}
public static class Binder extends AbstractBinder {
@Override
protected void configure() {
bind(VaryingParamValueFactoryProvider.class)
.to(ValueFactoryProvider.class)
.in(Singleton.class);
bind(VaryingParamValueFactoryProvider.Resolver.class)
.to(new TypeLiteral<InjectionResolver<VaryingParam>>() {
})
.in(Singleton.class);
}
}
}
आप जर्सी के साथ इस वर्ग 'Binder
(वर्ग के नीचे) रजिस्टर करने के लिए इसका इस्तेमाल करने की आवश्यकता होगी।
जर्सी QueryParamValueFactoryProvider
से इस कक्षा को अलग करता है यह है कि एनोटेशन के एक स्ट्रिंग मान को प्रोसेस करने की बजाय, यह मान को विभाजित करता है, और क्वेरी पैराम मानचित्र से मूल्य निकालने का प्रयास करता है। पाया गया पहला मूल्य वापस कर दिया जाएगा।यदि पैरामीटर List
या Set
है, तो यह अभी भी सभी विकल्पों को देख रहा है, और उन्हें सूची में जोड़ना जारी रखता है।
अधिकांश भाग के लिए यह @XxxParam
एनोटेशन से अपेक्षित सभी कार्यक्षमता रखता है। एकमात्र चीज जिसे कार्यान्वित करना मुश्किल था (इसलिए मैंने इस उपयोग के मामले का समर्थन छोड़ दिया), कई पैरामीटर हैं, उदा।
@GET
@Path("multiple")
public String getMultipleVariants(@VaryingParam("param-1|param-2|param-3") String value1,
@VaryingParam("param-1|param-2|param-3") String value2) {
return value1 + ":" + value2;
}
मैं वास्तव में यह है कि लागू करने के लिए मुश्किल होना चाहिए नहीं लगता कि, अगर तुम सच में इसकी जरूरत है, यह एक नया MultivaluedMap
बनाने, एक मूल्य को हटाने अगर यह पाया जाता है की बस एक बात है। इसे ऊपर VaryingParamFactory
की provide()
विधि में कार्यान्वित किया जाएगा। यदि आपको इस उपयोग के मामले की आवश्यकता है, तो आप इसके बजाय List
या Set
का उपयोग कर सकते हैं।
जर्सी टेस्ट फ्रेमवर्क का उपयोग करके, पूर्ण परीक्षण मामले के लिए this GitHub Gist (यह काफी लंबा है) देखें। आप QueryTestResource
में परीक्षण किए गए सभी उपयोग मामलों को देख सकते हैं, और जहां मैं के साथ ResourceConfig
परीक्षण configure()
विधि में Binder
पंजीकृत करता हूं।