As far as I can see, Jersey does not support deep-object parameters (parameters in the form of ?type[n1]=v1&type[n2]=v2).
Is it possible to add this as extension? And if so, how?
My idea is to have an annotation similar to #QueryParam, let's say #DeepObjectParam, and I would use it to annotate a field like this:
#GET
public Response(#DeepObjectParam("type") Map<String, String> type) {
// ...
}
And have Jersey inject the map.
Depending on the version of Jersey you are using, the interface that you need to implement will be different. In Jersey 2.0-2.25.1, the class is ValueFactoryProvider and 2.26+ it's ValueParamProvider.
With both classes, the implementation will be similar. There is one method to implement which takes a Parameter argument. We use this Parameter to check whether this provider is able to handle this type of parameter. If the check passes, then the method should return either a Factory or a Function (depending on the version) that provides the actual argument. If the check fails, it should return null.
For example, if the parameter is annotated with #DeepObjectParam and the parameter type is Map, then we should check for these two things.
#Override
public Function<ContainerRequest, ?> getValueProvider(Parameter param) {
if (param.isAnnotationPresent(DeepObjectParam.class) && isStringStringMap(param)) {
return new DeepParamFunction(param);
}
return null;
}
Here, the DeepParamFunction is a Function that takes a single ContainerRequest argument. It will do the parsing of the query parameter and then return the Map.
After you've implemented the required class, you need to register it with Jersey. Again, depending on which version of Jersey you are using, the registration will be different (but similar). In both cases you need to register an AbstractBinder with the ResourceConfig
register(new AbstractBinder() {
#Override
protected void configure() {
bind(DeepObjectParamProvider.class)
// 2.0-2.25.1 you will use ValueFactoryProvider.class
.to(ValueParamProvider.class)
.in(Singleton.class);
}
});
For both versions of Jersey, you will use the same AbstractBinder class, but the imports will be different. In 2.0-2.25.1, you will look for hk2 in the package name. In 2.26, you will look for jersey in the package name. The other difference is in the to() method. In 2.0-2.25.1 you will use ValueFactoryProvider and 2.26+, you will use ValueParamProvider.
Here is an example implementation of the ValueParamProvider (for Jersey 2.26+). The implementation for ValueFactoryProvider will be very similar
public class DeepObjectParamProvider implements ValueParamProvider {
#Override
public Function<ContainerRequest, ?> getValueProvider(Parameter param) {
if (param.isAnnotationPresent(DeepObjectParam.class) && isStringStringMap(param)) {
return new DeepParamFunction(param);
}
return null;
}
private static boolean isStringStringMap(Parameter param) {
if (!param.getRawType().equals(Map.class)) {
return false;
}
ParameterizedType type = (ParameterizedType) param.getType();
Type[] genericTypes = type.getActualTypeArguments();
return genericTypes[0].equals(String.class) && genericTypes[1].equals(String.class);
}
#Override
public PriorityType getPriority() {
// Use HIGH otherwise it might not be used
return Priority.HIGH;
}
private static class DeepParamFunction implements Function<ContainerRequest, Map<String, String>> {
private final Parameter param;
private DeepParamFunction(Parameter param) {
this.param = param;
}
#Override
public Map<String, String> apply(ContainerRequest request) {
Map<String, String> map = new HashMap<>();
DeepObjectParam anno = param.getAnnotation(DeepObjectParam.class);
String paramName = anno.value();
MultivaluedMap<String, String> params = request.getUriInfo().getQueryParameters();
params.forEach((key, list) -> {
// do parsing of params
});
return map;
}
}
}
For a complete running (2.26+) example, take a look at this post. For versions earlier than 2.26, I've refactored that example and posted it to this Gist.
P.S.
While implementing the provider and debugging, don't be surprised when the method is called more than once. What happens is that on startup, Jersey will validate all the resource methods and make sure that all the parameters are able to be processed. How Jersey does this is by passing each Parameter to all the providers until one is reached that doesn't return null. So the more resource methods you have, the more times your provider will be called. See this post for more elaboration.
Related
I have an interface
interface XXXCommandHandler(){
void parse(String something);
String response();
String additionalResponse();
}
Some of the classes that implement XXXCommandHandler do not implement additionalResponse().
I am using ApplicationContextManager.getInstance().getBeansOfType(XXXCommandHandler.class) to get the classes that implement XXXCommandHandler
Then call parse, response and additionalResponse
Since some do not implement additionalResponse I am forced to return null.
I can think of the following
Instead of returning null on classes that do not implement additionalResponse, declaire additionalResponse as default method and return null / or make it return Optional etc and override it on the classes that implement additionalResponse method.
Ugly way :- return null in all the classes that do not implement additionalResponse
Create two different interfaces XXXCommandHandlerParser() with parse and response method and XXXCommandHandlerAddtionalresponse() with additionalResponse method extending XXXCommandHandlerParser i.e
interface XXXCommandHandlerParser(){
void parse(String something);
String response();
}
interface XXXCommandHandlerAddtionalresponse()
extends XXXCommandHandlerParser {
String additionalResponse();
}
But if I do #3 I had to change
ApplicationContextManager.getInstance().getBeansOfType(XXXCommandHandlerAddtionalresponse.class).
If I do #4 then classes that do not implement additionalResponse or that do not implement XXXCommandHandlerAddtionalresponse will not be picked up.
Can you think of any elegant way?
It is a matter of taste which solution is more elegant but there is (at least) one more way to go:
Create a top level interface: interfaceA
Extend interfaceA to interfaceB with the extra method.
Collect beans of type interfaceA
If the instance is interfaceB than cast and call the extra method.
Maybe it is no more elegant than having a default implementation returning an optional.
Depending on what "additionalResponse" is, it might be ok to declare it in the base interface, add an implementation returning null (or an empty String?) to a base implementation and add the real implementations to the respective subclasses.
In real world problems, it usually helps to think about whether another developer might be surprised by the implementation you plan and might therefor use it in a way that leads to bugs.
If you want to go fancy, the Decorator Pattern might be a candidate.
While subclassing is usually frowned upon by the pattern gurus as it is used more often than justified, it's something people know and expect. That would be the solution #Zsolt V recommends (here as pseudo-code - might not compile):
Collection<XXXCommandHandler> baseHandlers = ApplicationContextManager.getInstance()
.getBeansOfType(XXXCommandHandler.class).values();
for (XXXCommandHandler baseHandler: basehHandlers) {
baseHandler.parse(something);
baseHandler.response();
if (baseHandler instanceof XXXCommandHandlerAddtionalresponse.class) {
XXXCommandHandlerAddtionalresponse additionalResponseHandler
= (XXXCommandHandlerAddtionalresponse) baseHandler:
additionalResponseHandler.additionalResponse();
}
}
I will also try to help you. From my point of view you can create an interface or direct class Response and return it instead of String. And there you can add method supportsAdditionalResponse and check it before getting additionalResponse. And in if additionalResponse is not supported then throw in getAdditionalResponse method UnsupportedOperationException.
From my point of view ApplicationContextManager.getInstance().getBeansOfType(XXXCommandHandler.class) is also not a good thing cause you are exposing your infrastructure. Better way will be to add method List getCommandHandlers() if it is possible.
public interface Response {
String getResponse();
default Boolean supportsAdditionalResponse() {
return false;
};
default String getAdditionalResponse() {
throw new UnsupportedOperationException();
}
}
public class HttpResponse implements Response {
private String response;
public HttpResponse(String response) {
this.response = response;
}
#Override
public String getResponse() {
return response;
}
}
public interface CommandHandler {
void parse(String command);
Response getResponse();
}
public class HttpCommandHandler implements CommandHandler {
private final Response response;
public HttpCommandHandler(Response response) {
this.response = response;
}
#Override
public void parse(String command) {
//do smth
}
#Override
public Response getResponse() {
return response;
}
}
So I have the following structure:
public abstract class Processor<T extends BaseContainer> {
protected abstract T initializeContainer(String requestID, Map<String, String> details);
protected abstract boolean validateContainer(T request);
protected abstract void process(T request);
public final process(String requestID, Map<String, String> details) {
T request = initializeContainer(requestID, details);
if (!validateContainer(request)) {
process(request);
}
}
}
public abstract class BaseContainer() {
protected final String requestID;
protected BaseContainer(String requestID, Map<String, String> details) {
this.requestID = requestID;
// set some other fields using details
}
}
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
public class SampleProcessor extends Processor<SampleContainer> {
#Override
protected SampleContainer initializeContainer(String requestID, Map<String, String> details) {
return new SampleContainer(requestID, details);
}
}
// SampleContainer can contain other details, but omitted for clarity
public class SampleContainer extends BaseContainer {
public SampleContainer(String requestID, Map<String, String> details) {
super(requestID, details);
}
}
I don't like the fact that I need to override initializeContainer for every Processor I add, especially when I don't change the constructor's parameters of Container (it will be always String requestID, Map<String, String> details
I understand that I can't simple call new T(requestID, details) in Processor. And I would imagine I will need some sort of factory (?) if I want to implement initializeContainer at base class.
Can you help to suggest anyway I can achieve this? Thank you.
Edit 1: I added two more methods to provide better context Processor
Everythings fine
This is a pattern called the abstract-factory.
Everytime I need to add a new Processor (with a corresponding new Container), I will need to:
This is the main intend of the pattern (ebenda)
the client (you) software creates a concrete implementation (your SampleProcessor) of the abstract factory (Processor) and then uses the generic interface of the factory to create (via initializeContainer) the concrete objects (your SampleContainer)...
I'd refactor the method name to createContainer, because that's what you do with your implementation - you don't setup an existing one but the make a new one.
Your simple example only calls the container constructor. But the 'processor creation and initialization' process could vary. Maybe, some processors for some container need special treatment. Then the implementations of the method would look different for each container subclass again.
An alternative common pattern, to solve this common problem, would be adding another abstract method like
public abstract Class<T> getProcessorType();
and implement it like this on every container implementation:
#Override
public Class<MyProcessor> getProcessorType() {
return MyProcessor.class;
}
The base class then could implement the create method for processors:
public T createProcessor(String requestID, Map<String, String> details) {
T processor;
try {
processor = getProcessorType().newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace(); // or handle correctly
}
processor.init(requestId, details)
return processor;
}
(Note that this requires a no-args processor constructor)
Not sure if the title does this justice. I am kind of new to Java and trying to figure out how to have a single class use different "services". Let say I have an APIRequest class, this class needs to be able to use different APIs depending on what is needed. Example. I need to ship a package, if the package is below 32OZ I need to use Endicia, else I need to use FedEx. I have 2 "service" classes FedexRequest and EndiciaRequest. I am trying to allow the APIRequest class use either one depending on what the weight of the package. I created a class called APIService that has a static method called getService. it just creates a map of string name -> request class like so...
public class APIService {
private static Map<String, Object> services = new HashMap<>();
private static final Map<String, String> availableServices = new HashMap() {{
put("fedex", "FedexRequest");
put("endicia", "EndiciaRequest");
}};
public static Object getService(String type) {
if(services.containsKey(type)) {
return services.get(type);
}
return null;
}
static {
for(Map.Entry<String, String> serv : availableServices.entrySet()) {
try {
Class<?> cls = Class.forName(serv.getValue());
services.put(serv.getKey(), cls.newInstance());
} catch(Exception e) {
services.put(serv.getKey(), new Class[1]);
}
}
}
}
So now I can call APIService.getService("fedex"); however I am having a really hard time trying to figure out how to use that in my APIRequest class, because I would need to do something like...
this.service = (FedexRequest) APIService.getService("fedex");
//or
this.service = (EndiciaRequest) APIService.getService("endicia);
but that breaks the whole dynamic part of the equation, what if I need to add another service later?
I tried having both FedexRequest and EndiciaRequest implement a Request interface, then use
this.service = (Request) APIService.getService("fedex");
but that gives me a Java.lang.Class error saying it cannot be cast to Request. I am assuming it is because Request is an interface so you cannot use cls.newInstance() on an implementing class then cast to the interface.
I am really lost on how to allow my APIRequest class to use either FedexRequest or EndiciaRequest, without specifically using the type casting, so that it can be dynamic and we could add a service later without recoding the whole thing. I come from PHP where this would be extremely simple, since you do not have to explicitly define a type. Any help would be greatly appreciated. Thank you.
If I were you I would do the following:
This is the implementation of Service interface:
public interface Service {
public void performAction();
//other common functions...
}
A small modification to your APIService class:
public class APIService {
private static Map<String, Service> services = new HashMap<>();
private static final Map<String, String> availableServices = new HashMap() {{
put("fedex", "com.finity.shipping.api.fedexapi.FedexRequest");
put("endicia", "com.finity.shipping.api.endiciaapi.EndiciaRequest");
}};
public static Service getService(String type) {
return services.get(type);
}
static {
for(Map.Entry<String, String> serv : availableServices.entrySet()) {
try {
Class<?> cls = Class.forName(serv.getValue());
services.put(serv.getKey(), cls.newInstance());
} catch(Exception e) {
services.put(serv.getKey(), new Class[1]);
}
}
}
}
Every time you need a service to be added to your application just implement the Service interface:
public class FedexRequest implements Service {
public void performAction() {
//do something
}
}
And finally in your class where you use this.service:
Service service;
...
this.service = APIService.getService("fedex");
this.service.performAction();
Pooya solution is good.
I will add something. You use some strings to represent things which are typable : constants and classes. Using reflection to initialize a factory where you handle only classes written in hard in some strings(for example com.finity.shipping.api.fedexapi.FedexRequest) and belonging to your own project seems to be a overhead.
In case where your factory don't know which classes it will instantiate, using reflection is meaningful. But it seems not be the case.
Besides, FEDEX and ENDICIA could be constant by using enum. It allows to type them and to avoid bad suprpises.
We would expect that your factory be more simple. Here an example :
public class APIService {
public static enum TypeRequest{
FEDEX, ENDICIA;
}
private static Map<String, Service> services = new HashMap<>();
static {
services.put(FEDEX, new FedexRequest());
services.put(ENDICIA, new EndiciaRequest());
}
public static Service getService(TypeRequest typeRequest) {
return services.get(typeRequest);
}
}
I have the following very simple interface:
public interface IDataSource<T> {
Observable<T> observable();
}
Now I'll be having multiple implementations of it. Each of those implementation may rely on varying parameters (different storage objects: JDBC, Cassandra, Redis...). So for instance I'll have:
public class CassandraDataSource implements IDataSource<MyCassandraObject> {
#Inject
public CassandraDataSource(Keyspace ks) {
// ...
}
}
public class OtherCassandraDataSource implements IDataSource<MyOtherCassandraObject> {
#Inject
public OtherCassandraDataSource(Keyspace ks) {
// ...
}
}
public class JDBCDataSource implements IDataSource<MyJdbcObject> {
#Inject
public JDBCDataSource(Database db) {
// ...
}
}
And so on.
What I would like is to reference each of those with a string so that i can call a factory which would return the appropriate IDataSource. Something that would behave like that:
public class DataSourceFactory {
public static final Map<String, Supplier<IDataSource<?>>> map = new HashMap<>();
#SuppressWarnings("unchecked")
public <T> IDataSource<T> get(String ref) {
return (IDataSource<T>) map.get(ref).get();
}
}
I could be giving N Providersas parameters (or direct field injection) to my factory (N being the number of IDataSource I use) and map strings to those in the constructor or use a switch in the get method but this would become quite a mess once I reach 10 to 20 IDataSource (or more!)
Is there some simpler solution I've been overlooking ?
Thanks
If you have to have a factory, then no—as in this question a manual factory is probably the best you can get.
However, if you bind all of your IDataSource implementations to IDataSource with different binding annotations, then you might be able to skip the factory and simply inject #Source("foo") IDataSource and get back the instance you want. The configuration between String and implementation still has to live somewhere, but you can have it live in a Guice module if you'd like. And, by injecting the Injector and supplying a compatible annotation implementation, you can even write a factory like DataSourceFactory that defers to Guice.
As a side note, beware of your DataSourceFactory; get will have no safe way to supply a value for its type parameter T.
We have a situation where we provide an external configuration in form of a Map to our running programs. I have found that JSR-330 Dependency Injection gives a much cleaner way to use that configuration map in the code instead of passing the map around or to use JNDI to get it.
#Inject #Named("server.username") String username;
lets the JSR-330 implementation fill in this field automatically.
With Guice I can set the value with
bindConstant().annotatedWith(Names.named(key)).to(value);
I would like to be able to do the same in Weld (bind "server.username" to e.g. "foobar") and I understand that the mechanism most likely is beans.xml, but I would prefer a simple "feed this map to Weld, please" code alternative. What would be a good way to do this?
EDIT 2013-10-16: After looking into Dagger which works at compile time and not runtime, I found that with us usually having 10-20 per program we could live with having a #Provider method for each configuration string which then looks up in the configuration map. This allows for method specific behavior (including default values), ability to provide javadoc, and ability to put all these methods in the same class. Also it works well with Weld out of the box. I am considering writing a fuller explanation in a blog entry.
I'd like that bounty now please. Figuring this out taught me quite a bit about the innards of WELD, and here's the most interesting lesson: #Named is a qualifier, and must be treated as such if you are going to be able to match against it.
I do have a warning for you: If you are missing any values in your app, it will fail at deploy or load time. This may be desirable for you, but it does specifically mean that "default" values are not possible.
The injection point is specified exactly as you have above, and here's the extension code needed to make it work:
#ApplicationScoped
public class PerformSetup implements Extension {
Map<String, String> configMap;
public PerformSetup() {
configMap = new HashMap<String, String>();
// This is a dummy initialization, do something constructive here
configMap.put("string.value", "This is a test value");
}
// Add the ConfigMap values to the global bean scope
void afterBeanDiscovery(#Observes AfterBeanDiscovery abd, BeanManager bm) {
// Loop through each entry registering the strings.
for (Entry<String, String> configEntry : configMap.entrySet()) {
final String configKey = configEntry.getKey();
final String configValue = configEntry.getValue();
AnnotatedType<String> at = bm.createAnnotatedType(String.class);
final InjectionTarget<String> it = bm.createInjectionTarget(at);
/**
* All of this is necessary so WELD knows where to find the string,
* what it's named, and what scope (singleton) it is.
*/
Bean<String> si = new Bean<String>() {
public Set<Type> getTypes() {
Set<Type> types = new HashSet<Type>();
types.add(String.class);
types.add(Object.class);
return types;
}
public Set<Annotation> getQualifiers() {
Set<Annotation> qualifiers = new HashSet<Annotation>();
qualifiers.add(new NamedAnnotationImpl(configKey));
return qualifiers;
}
public Class<? extends Annotation> getScope() {
return Singleton.class;
}
public String getName() {
return configKey;
}
public Set<Class<? extends Annotation>> getStereotypes() {
return Collections.EMPTY_SET;
}
public Class<?> getBeanClass() {
return String.class;
}
public boolean isAlternative() {
return false;
}
public boolean isNullable() {
return false;
}
public Set<InjectionPoint> getInjectionPoints() {
return it.getInjectionPoints();
}
#Override
public String create(CreationalContext<String> ctx) {
return configValue;
}
#Override
public void destroy(String instance,
CreationalContext<String> ctx) {
// Strings can't be destroyed, so don't do anything
}
};
abd.addBean(si);
}
}
/**
* This is just so we can create a #Named annotation at runtime.
*/
class NamedAnnotationImpl extends AnnotationLiteral<Named> implements Named {
final String nameValue;
NamedAnnotationImpl(String nameValue) {
this.nameValue = nameValue;
}
public String value() {
return nameValue;
}
}
}
I tested that this worked by making a WELD-SE app:
#ApplicationScoped
public class App {
#Inject
#Parameters
List<String> parameters;
#Inject
#Named("string.value")
String stringValue;
public void printHello(#Observes ContainerInitialized event) {
System.out.println("String Value is " + stringValue);
}
}
Lastly, don't forget /META-INF/services/javax.enterprise.inject.spi.Extension, replacing weldtest with the classpath you use:
weldtest.PerformSetup
That should make all of this work. Let me know if you run into any difficulties and I'll send you my test project.
Not all that interested in the bounty, but I'll take it if it's still on the table. This is VERY similar to some code I'm using at $DAYJOB, and so this isn't theory, it's what I use in production code, but modified to protect the guilty. I haven't tried compiling the modified code, so be warned that I may have made some errors in changing names and such, but the principles involved here have all been tested and work.
First, you need a Value Holder Qualifier. Use #Nonbinding to keep WELD from matching ONLY to qualifiers with identical values, since we want all values of this particular qualifier to match a single injection point. By keeping the qualifier and value in the same annotation, you can't just "forget" one of them by accident. (KISS principle)
#Qualifier
#Retention(RUNTIME)
#Target({METHOD, FIELD, PARAMETER, TYPE})
public #interface ConfigValue {
// Excludes this value from being considered for injection point matching
#Nonbinding
// Avoid specifying a default value, since it can encourage programmer error.
// We WANT a value every time.
String value();
}
Next, you need a producer method which knows how to get the Map. You should probably have a Named bean which holds the producer method, so you can either explicitly initialize the value by using getters/setters, or else have the bean initialize it for you.
We must specify a blank value for the qualifier on the producer method to avoid compile time errors, but it's never used in practice.
#Named
public class ConfigProducer {
//#Inject // Initialize this parameter somehow
Map<String,String> configurationMap;
#PostConstructor
public void doInit() {
// TODO: Get the configuration map here if it needs explicit initialization
}
// In general, I would discourage using this method, since it can be difficult to control exactly the order in which beans initialize at runtime.
public void setConfigurationMap(Map<String,String> configurationMap) {
this.configurationMap = configurationMap;
}
#Produces
#ConfigValue("")
#Dependent
public String configValueProducer(InjectionPoint ip) {
// We know this annotation WILL be present as WELD won't call us otherwise, so no null checking is required.
ConfigValue configValue = ip.getAnnotated().getAnnotation(ConfigValue.class);
// This could potentially return a null, so the function is annotated #Dependent to avoid a WELD error.
return configurationMap.get(configValue.value());
}
}
Usage is simple:
#Inject
#ConfigValue("some.map.key.here")
String someConfigValue;
It may be possible to implement this as an #Dependent Producer method that itself injects an #InjectionPoint which would allow you to reflect upon the field you're being injected into -- this would let you peek into a custom annotation (not a qualifier) member on the field to figure out the val you want to return
#Inject #ConfigMapQualifier #Val("user.name") String user;
...
#Produces #ConfigMapQualifier configProducr(...) {
...
#Inject InjectionPoint ip;
// use e.g. ip/getJavaMember() then reflection to figure out the #Val value membr.
Would implementing a custom Weld InjectionServices not be an option here ?
what about
#Resource(name = "server.username", type = java.lang.String.class)
private String injectTo;
Javadoc: http://download.oracle.com/javase/6/docs/api/javax/annotation/Resource.html