I've been searching everywhere, but can't seem to find a clear answer...
What is the mechanism whereby a server (glassfish for my problem) injects actual objets that are annotated with #Context? More specifically, if I wanted to write a class that did something like:
#Path("/")
public class MyResource {
#GET
public String doSomething(#Context MyObject obj) {
// ...
}
}
then how would I do it? Where is it that the MyObject is instanciated, who does it, and how?
Edit: I've seen stuff like the following:
Using #Context, #Provider and ContextResolver in JAX-RS
http://jersey.576304.n2.nabble.com/ContextResolver-confusion-td5654154.html
However, this doesn't square with what I've seen, e.g. in the constructor of org.neo4j.server.rest.web.RestfulGraphDatabase, which has the following signature:
public RestfulGraphDatabase(
#Context UriInfo uriInfo,
#Context Database database,
#Context InputFormat input,
#Context OutputFormat output,
#Context LeaseManager leaseManager )
You can write your own injection provider and plug that into Jersey - look at SingletonTypeInjectableProvider and PerRequestTypeInjectableProvider - extend one of these classes (depending on the lifecycle you want for the injectable object) and register your implementation as a provider in your web app.
For example, something like this:
#Provider
public class MyObjectProvider extends SingletonTypeInjectableProvider<Context, MyObject> {
public MyObjectProvider() {
// binds MyObject.class to a single MyObject instance
// i.e. the instance of MyObject created bellow will be injected if you use
// #Context MyObject myObject
super(MyObject.class, new MyObject());
}
}
To include the provider in your web app you have several options:
if your app uses classpath scanning (or package scanning) just make sure the provider is in the right package / on the classpath
or you can simply register it using META-INF/services entry (add META-INF/services/com.sun.jersey.spi.inject.InjectableProvider file having the name of your provider class in it's contents)
I think I may be on to something...and if this works, Martin should get partial credit. :)
It appears that the #Provider class must implement the com.sun.jersey.spi.inject.Injectable<T> interface. However, I'm not sure that this is enough to actually have the #Context be injected. What's missing, is that we have to tell the ResourceConfig object of the web app about the #Provider. In the context of what I'm trying to do, and taking hints from neo4j-server, the remaining work boils down to:
extending com.sun.jersey.spi.container.servlet.ServletContainer, and overriding the configure method:
#Override
protected void configure(WebConfig wc, ResourceConfig rc, WebApplication wa)
{
super.configure( wc, rc, wa );
Set<Object> singletons = rc.getSingletons();
singletons.add(new MyObjectProvider());
}
specifying that this container must be used in the web.xml deployment descriptor:
<servlet>
<servlet-name>JAX-RS Servlet Container</servlet-name>
<servlet-class>com.blah.MyServletContainer</servlet-class>
</servlet>
I don't think you can use #Context with a user-defined type like MyObject. It is for injecting types that jax-ws already understands. It is mentioned here.
Chapter 5 of the JAX-RS specification presents all the standard JAX-RS Java types that may be used with #Context.
You probably want to use something like #FormParam or #PathParam instead. See section 2.3 of the spec for a description. Here is your answer, copied from that section of the spec:
In general the Java type of the method parameter may:
Be a primitive type;
Have a constructor that accepts a single String argument;
Have a static method named valueOf or fromString that accepts a single String argument (see, for example, Integer.valueOf(String) and java.util.UUID.fromString(String)); or
Be List, Set or SortedSet, where T satisfies 2 or 3 above. The resulting collection is read-only.
See chapters 5-6 of the JAX-RS spec. That should tell you everything you need to know about it.
Related
I want to define a annotation like #PlatformRelated, once it is marked in a interface, there will be a proxy bean at spring context, and this proxy bean should be #Priority.I want this proxy could invoke different implement according to key parameter #KeyPrameter.And I still wanna use spring features like #Async,#Trasaction,etc... at my Implement1 and Implement2.
#PlatformRelated
interface MyInterface {
method(#KeyPrameter String parameter);
}
#Component
class Implement1 implements MyInterface {
method(String parameter){
//do something 111
}
}
#Component
class Implement2 implements MyInterface {
method(String parameter){
//do something 222
}
}
#Service
class BusinessService{
#Autowired
private MyInterface myInterface;
public void doSomething() {
myInterface.method("key1");
//Implement1 work
myInterface.method("key2");
//Implement2 work
}
}
Do you guys have some good idea to complete it?
I must admit I haven't totally understood the meaning #Priority, however, I can say that if you want to implement this feature in spring, you should probably take a look at Bean Post Processors.
BeanPostProcessors are essentially a hook to Bean Creation process in spring intended for altering bean behavior.
Among other things, they allow wrapping the underlying bean into the proxy (CGLIB/java.lang.Proxy if you're working with interfaces, or even using programmatically Spring AOP), these proxies can provide a hook to the method execution that can read your annotations (like mentioned #KeyParameter) and execute a code in a way similar to Aspect's code that you already make use of.
Not all bean post processor wrap the bean into the proxy. For example, if you want to implement a BPP that uses "#Autowire", you will return the same bean, just "inject" (read, put by reflection) its dependencies. On the other hand, if you want to implement with BPP #Transactional behavior, then yes, you should wrap the bean into a proxy that would take care of transaction management capabilities before and after the method execution.
It's totally ok to have a spring bean that gets "altered" by many post processors, some of them would wrap it into a proxy other will just modify-and-return the same bean, If there are many BPP-s that wrap the bean into proxy we'll get "proxy inside proxy inside proxy" (you get the idea). Each layer of proxy will handle one specific behavior.
As an example, I suggest you take a look at existing Spring postprocessors, or, for instance, a source code of the following library: Spring Boot metering integration library
This library contains some implementations of post processors that allow metrics infrastructure integration by defining annotations on methods of Spring Beans.
I'm using a bunch of microservices in my project. These microservices all share one common endpoint that returns an object which has been parsed through XML.
Now I'd love to have some kind of default method defined within the Annotation like this:
#RestController
public #interface ComaModule {
Class<? extends Object> clazz();
#RequestMapping("/descriptor")
default ModuleDescriptor getDescriptor() {
ModuleXmlUnmarshaller moduleXmlUnmarshaller = new ModuleXmlUnmarshaller(clazz());
Optional<ModuleDescriptor> moduleDescriptorOptional = moduleXmlUnmarshaller.findModuleDescriptor();
return moduleDescriptorOptional.orElse(null);
}
}
That does not work since I am not able to have a method definition in my annotation. So the hard stuff is that I want to keep #RequestMapping("/descriptor") for this.
In fact I want some kind of aspect for every RestController I use. I read about AOP for Spring and Proxy but thought I might be able to achieve this with Annotations.
May be you can try adding annotation processor class, where you can write the code which have in your post and achieve what your goal.
Servlet 3.0-enabled containers allows us to skip the web.xml servlet configuration and automatically scan your code for resources and providers once you extend javax.ws.rs.core.Application, annotate it with #ApplicationPath and do not override the getClasses() method. (hope I got all of that right :\)
At the moment I am using the Jersey implementation and securing resource methods using #RolesAllowed annotations. For this I need to register the org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature Provider class, however, the only ways I'm aware of to do this is either to:
Register the class in the getClasses() method of my Application class (which, I think, will cause the Servlet 3.0 container NOT to auto-scan)
Continue to use the web.xml Jersey servlet setup with
<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature</param-value>
</init-param>
Now the context behind this question is that I might have to switch to using RESTeasy and if I use option 1 it adds a Jersey dependency in the code and the code is no longer generic.
How do I write my code to use security annotations while maintaining generic JAX-RS code that could be deployed to another Servlet 3.0 JAX-RS implementation?
One option is to use a javax.ws.rs.core.Feature (a JAX-RS standard class). You can register any components there, and then annotate the class with #Provider, and it will be picked up like any other #Provider or #Path annotated class
#Provider
public class MyFeature implements Feature {
#Overrride
public boolean configure(FeatureContext context) {
context.register(RolesAllowedDynamicFeature.class);
}
}
Do note that since you are using the Jersey feature, your app is no longer implementation independent, so you might as well use Jersey all the way. For one, Jersey does not recommend scanning the class-path, which is the affect of doing what you are doing. Instead Jersey has a mechanism that allows you to recursively scan a package (and its sub-packages). So you could instead do
#ApplicationPath("..")
public class AppConfig extends ResourceConfig {
public AppConfig() {
packages("the.packages.to.scan");
register(RolesAllowedDynamicFeature.class);
}
}
Note that ResourceConfig is a sub-class of Application
See Also:
When to Use JAX-RS Class-path Scanning Mechanism
Sevlet Based Deployment - Servlet 3.x Container
Note:
If you wanted to stick to the classpath scanning mechanism, and wanted to keep the project independent of any Jersey dependencies, you could also override Map<String, Object> getProperties() in the Application class. In the returned Map, you could add the property that you would otherwis have added in the web.xml
#Override
public Map<String, Object> getProperties() {
Map<String, Object> props = new HashMap<>();
props.put("jersey.config.server.provider.classnames",
"org.glassfish.jersey.server.filter.RolesAllowedDynamicFeature");
return props;
}
But even though the source code is implementation independent, the application is still dependent on the Jersey roles feature. If you decided you wanted to port, you would still need a replacement for the feature.
If you wanted to stay completely independent, you could implement the feature yourself. It's not all that complicated. You can check out the source code for RolesAllowedDynamicFeature. If you decide to try and implement the same, just annotate your implementation class with #Provider, and it should get picked up.
I'm using Tomcat 6.0.33 with Java 6. I have this servlet ...
public class SaveXmlServlet extends HttpServlet {
private CacheService cacheService;
public void init(ServletConfig config) throws ServletException {
cacheService = CacheServiceLocator.cacheService();
} // init
How can I redesign my servlet to ...
Take advantage of dependency injection so that a mocking framework like mockito can inject its own "cacheService" implementation
Guarantee that there is only one instance of cacheservice in my jvm. Right now the line "CacheServiceLocator.cacheService()" guarantees this.
? I'm not using (or allowed to use) frameworks like Spring or Guice. Grateful for any thoughts on refactoring this. Thanks, - Dave
There are a few options, although I recommend smacking someone for not "letting" you use a framework. Two quickies; I'm sure there are others. I'd go the smacking route first.
You can mock static classes using a combination of EasyMock/Mockito and, say, PowerMock. Technically you don't need to change anything at all to get the in-test behavior you want.
A class name provided by a servlet init parameter or JNDI resource could be used to create an instance of the cache locator. Providing a setter for the same allows a unit/etc. test to set it on the class.
Is JSR-303 also intended for method parameter validation?
If so, is there any example on the web? The biggest challenge I'm facing is how to get a validator within each method. With Spring 3, doesn't it mean that I'd have to inject virtually every class with a LocalValidatorFactoryBean?
Thanks!
Method level validation will be supported in the upcoming version 4.2 of JSR 303's reference implementation Hibernate Validator.
As pointed out in the previous answer this will allow constraint annotations (built-in as well as custom defined types) to be specified at method parameters and return values to specify pre- and post-conditions for a method's invocation.
Note that HV will only deal with the actual validation of method calls not with triggering such a validation. Validation invocation could be done using AOP or other method interception facilities such as JDK's dynamic proxies.
The JIRA issue for this is HV-347 [1], so you might want to add yourself as watcher to this issue.
[1] http://opensource.atlassian.com/projects/hibernate/browse/HV-347
The javadocs for each of the JSR 303 annotations tells the following:
#Target(value={METHOD,FIELD,ANNOTATION_TYPE,CONSTRUCTOR,PARAMETER})
See, PARAMETER is there. So, yes, it's technically possible.
Here's an example:
public void method(#NotNull String parameter) {
// ...
}
I'm however not sure how that integrates with Spring since I don't use it. You could just give it a try.
In Spring 3.1.0 you can use #Validated annotation to activate validation on a pojo.
Create an interface for the pojo class an put this annotation over it, then add your validation annotations in the methods definitions. ( the interface is required because Spring will create a proxy class using the interface as definition )
#Validated
public interface PojoClass {
public #NotNull String doSomething(#NotEmpty String input);
}
your pojo :
public class PojoClassImpl implements PojoClass {
public String doSomething(String input) {
return "";
}
}
Starting from a standard spring web application with active validation, remember to add in your spring configuration this bean declaration:
<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
This sounds like a use case for AOP (AspectJ). Write a pointcut for methods that are annotated with javax.validation.constraints.*, inject a validator into the aspect (probably using Spring) and use a #Before or #Around advice to perform the validation before method execution.
Read AspectJ in Action for reference.
You can use jcabi-aspects (I'm a developer), which integrates JSR 303 with AspectJ. Actual validation is done by one of JSR 303 implementations, which you will have to add to class path, like Hibernate Validator, or Apache BVal.