Hi All,
I’m trying to write a custom context injectable provider that maps request form params to Form (a class of ours) object fields which are strongly-typed and would like to reuse jersey’s built-in StringReaderWorkers to do the string -> instance-of-type conversions.
The idea being that I can define Form subclasses and then use `_at_Conext SubclassOfForm form` injection on resource methods.
There doesn’t seem to be an obvious way to obtain an instance of StringReaderWorkers from within a Provider.
I was initially using Jersey injection to obtain an instance of ProviderServices in my InjectableProvider subclass constructor. I could then later create an instance of StringReaderFactory and call `stringReaderFactory.init(providerServices)` with the obtained ProviderServices instance. I found that trying to jersey-inject StringReaderWorkers directly in the ctor failed due to a race condition; InjectableProviders are created/inited in the WebApplicationImpl before StringReaderWorkers.
I’d like to use Guice injection (i’m using jersey-guice) on our Form subclasses and thus had to switch to Guice injection on my InjectableProvider subclass ctor to obtain an Injector instance. I found that I can access an instance of my WebApplication and obtain a ServerInjectableProviderContext, which I can then use to “inject” a StringReaderWorkers instance.
I’ve included a copy of my InjectableProvider below. I’d appreciate it if somebody could have a look and let me know if there is a better method of obtaining the StringReaderWorkers instance used by the FormInjectable (inner class).
Regards,
Adam
@Provider
public class FormProvider implements InjectableProvider<Context, Class> {
private final Injector injector;
@Inject
public FormProvider(Injector injector) {
this.injector = injector;
}
public class FormInjectable extends AbstractHttpContextInjectable<Form> {
private final StringReaderWorkers stringReaderWorkers;
private final Class<? extends Form> clazz;
public FormInjectable(StringReaderWorkers stringReaderWorkers, final Class<? extends Form> clazz) {
this.stringReaderWorkers = stringReaderWorkers;
this.clazz = clazz;
}
@Override
public Form getValue(HttpContext c) {
final Form form = injector.getInstance(clazz);
final com.sun.jersey.api.representation.Form params = c.getRequest().getFormParameters();
for (final Map.Entry<String, Form.Field> fieldEntry: form.fields.entrySet()) {
final Form.Field field = fieldEntry.getValue();
final String rawParam = params.getFirst(fieldEntry.getKey());
try {
final Object param = stringReaderWorkers.getStringReader(field.type.getRawType(), field.type.getType(), null).fromString(rawParam);
field.withValue(param);
} catch (NullPointerException e) {
// ignore -- field will be null
} catch (ExtractorContainerException e) {
field.withRawValue(rawParam).withValid(false).withMessage("Please provide a valid value.");
}
}
form.validate();
return form;
}
}
@Override
public Injectable<Form> getInjectable(final ComponentContext ic, final Context a, final Class clazz) {
if (!Form.class.isAssignableFrom(clazz))
return null;
final WebApplication webApp = injector.getInstance(WebApplication.class);
final ServerInjectableProviderContext sipc = webApp.getServerInjectableProviderFactory();
final StringReaderWorkers srw = (StringReaderWorkers) sipc.getInjectable(new Parameter(ic.getAnnotations(), a, null, null, StringReaderWorkers.class, StringReaderWorkers.class), null).getValue();
return new FormInjectable(srw, clazz);
}
@Override
public ComponentScope getScope() {
return ComponentScope.PerRequest;
}
}
- application/pkcs7-signature attachment: smime.p7s