If an application is built with several components, is there a way to have a #Path prefix for resources inside a component?
As an example, let's consider this service for retrieving info about several universities from a city. The components would be schoolA and schoolB.
amsterdam-schools.com/schoolA/students/
amsterdam-schools.com/schoolA/teachers/
amsterdam-schools.com/schoolA/teachers/{id}
amsterdam-schools.com/schoolA/teachers/{id}/courses
...
amsterdam-schools.com/schoolB/teachers
amsterdam-schools.com/schoolB/students
...
Is it possible to implement somthing like the code below?
#Path("/schoolA")
public abstract class SchoolA {
// ...
}
#Path(#SuperPath + "/teachers")
public class TeacherListResource extends SchoolA {
#Path("/{id}")
public Response get(#PathParam("id") Integer teacherId) {
// ...
}
// ...
}
I know #SuperPath doesn't exist, but what would be the best practice not to write "SchoolA" in every resource class? :D
You can deploy multiple JAX-RS applications with different URIs in one WAR.
You will have to create one javax.ws.rs.core.Application subclass per such an application (or use web.xml for this purpose).
And you will have to explicitly configure resources in each subclass by overriding the getClasses or getSingletons method:
#Path("first")
public class FirstResource {
#GET
public String first() {
return "first";
}
}
#ApplicationPath("one")
public class JAXRSConfigurationOne extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(FirstResource.class);
return resources;
}
}
#Path("second")
public class SecondResource {
#GET
public String first() {
return "second";
}
}
#ApplicationPath("two")
public class JAXRSConfigurationTwo extends Application {
#Override
public Set<Class<?>> getClasses() {
Set<Class<?>> resources = new HashSet<>();
resources.add(SecondResource.class);
return resources;
}
}
Both JAX-RS applications become accessible through distinct URIs:
http://localhost:8080/multiple-roots/one/first
http://localhost:8080/multiple-roots/two/second
For more details, have a look here.
Yes, normally if you are using Jersey, for each component you have to define an Application class that extends javax.ws.rs.coreApplication. In this class also you will have to define an #ApplicationPath.
For instance :
#ApplicationPath("/my-base-url-for-my-component")
public class MyComponent extends Application {}
All ressources defined in MyComponent will be prefixed with /my-base-url-for-my-component.
Related
I have created REST controller with base request mapping on class.
#RestController
#RequestMapping(".../{type}/{typeId}/param..")
public class FooController{
#Autowired
BarServiceProxy proxy;
public List<Foo> getFoo(){
return proxy.get(getType());
}
/*
public Type getType(???){
return type;
}
*/
}
Next I have enum Type which determines what service will be used by proxy service (ie. proxy has injected list of serivces and gets one that supports type). I am wondering if there is any way how to make part of request mapping {type} and get it in getter method below so I don't have to repeat it in every request mapping in this class.
I only figured one alternative solution - make this class abstract and then extend it and return constant. This would however leave me with lot of classes without any added value. For example:
#RequestMapping(".../{typeId}/param..")
public abstract class FooController{
#Autowired
BarServiceProxy proxy;
public List<Foo> getFoo(){
return proxy.get(getType());
}
protected abstract Type getType();
}
#RestController
#RequestMapping("/typeAbc)
public class TypeAbcFooController extends FooController{
public Type getType{
return Type.Abc;
}
}
So is it possible to bind #PathVariable from URL specified on class #RequestMapping in some shared method? Thanks
I hope i've understood your problem, but one way of improving your design could be to implement a strategy per type, to inject them, and to use them corresponding to your type received in your controller.
Exemple:
public enum MyType {
TYPE1,
TYPE2
}
public interface IService {
MyType getHandledType();
List<Foo> getFoo();
}
#Service
public class Type1Service implements IService {
#Override
public MyType getHandledType() {
return MyType.TYPE1;
}
#Override
public List<Foo> getFoo() {
// IMPLEMENTATION FOR TYPE1;
}
}
public class FooController{
#Autowired
List<IService> services;
public List<Foo> getFoo(MyType requestType){
IService service = services.stream().filter(iService -> iService.getHandledType() == requestType).findFirst().get();
return service.getFoo();
}
}
This way your controller is agnostic of the underlying service implementation, which is a big responsability.
I have an interface I and 2+ of its implementations/services (ex. I1, I2)
public interface I {
void handle();
Network getNetwork();
}
and I have another one service (ex. IHolder) that is injecting the list of all services that implementing I and is putting it to its inner private map field where key is some unique Enum (interface has public method that returns one) and value the implementation itself.
public class IHolder {
private final Map<Network, I> iByNetwork = new HashMap<>();
public IHolder(List<I> is) {
for (I i : is) {
register(i.getNetwork(), i);
}
}
private void register(Network network, I i) {
this.iByNetwork.put(network, i);
}
public I getI(Network network) {
return iByNetwork.get(network);
}
}
Now I want to inject IHolder to my test class to use his map filled with those services
So basically annotate the IHolder class with #Service, but you won't be able to use it's private field (map), at least not in a simple way...
edit
Try to add these annotations to your test classes:
#RunWith(SpringRunner.class)
#SpringBootTest
I am using Java 8 with a Play framework. My goal is to inject a map whose keys are enum values and values are implementations of a specific interface.
Here is my enum:
public enum Service {
HTML("html"), TEXT("txt");
private String serviceId;
Service(String serviceId) { this.serviceId = serviceId; }
}
I have Executable interface
public interface Executable { void execute(); }
and two classes that implement it:
public class HtmlWorker implements Executable { ... }
public class TextWorker implements Executable { ... }
I would like to be able to inject Map<Service, Executable> serviceMap so I can have access to a specific implementation using a Service key:
public class Processor {
#Inject
Map<Service, Executable> serviceMap;
public void doStuff() {
Executable htmlService = this.serviceMap.get(Service.HTML);
Executable textService = this.serviceMap.get(Service.TEXT);
// do more stuff
}
}
I added bindings to the module class:
public class AppModule extends AbstractModule {
#Override
protected void configure() {
MapBinder<Service, Executable> serviceBinder = MapBinder
.newMapBinder(binder(), Service.class, Executable.class);
serviceBinder.addBinding(Service.HtmlService).to(HtmlWorker.class);
serviceBinder.addBinding(Service.TextService).to(TextWorker.class);
}
The problem is that serviceMap is never injected and it is always null inside Processor. What am I missing?
According to the official MapBinder documentation the MapBinder.addBinding should take the map's key.
As far as concerning your provided example what about changing AbstractModule's code from:
serviceBinder.addBinding(Service.HtmlService).to(HtmlWorker.class);
serviceBinder.addBinding(Service.TextService).to(TextWorker.class);
to
serviceBinder.addBinding(Service.HTML).to(HtmlWorker.class); // <-- see the enum constant here?
serviceBinder.addBinding(Service.TEXT).to(TextWorker.class);
Anyway I don't know where the class Service.HtmlService in your example comes from since you didn't state it anywhere.
#Path("/test")
public class MyClass {
#GET
public Response response() {
// Generating some expensive object here.
}
Right now I load the data into arrays etc inside the "response" function, but I want to do it before the query is even made. This way, I want to avoid reloading the data every time a a query is made. How do I achieve this?
This depends on your framework. Are you using the reference implementation Jersey? Jersey comes bundled with HK2 automatically. Then you could add
#Path("/test")
public class MyClass {
#Inject
private MyState stateful;
// here comes your code...
}
to your resource. Of course, you would still need to configure what to inject into this field. With HK2, you use an AbstractBinder for this purpose:
class MyBinder extends AbstractBinder {
private final MyState stateful;
public MyBinder (MyState stateful) {
this.stateful = stateful;
}
#Override
protected void configure() {
bind(stateful).to(MyState.class);
}
}
Finally, you need to add this binder on the application's setup. For this purpose, JAX-RS Application object can be queried for singletons. Simply add the required instance to the application such that it is returned by Application#getSingletons as here:
class MyJaxRSApplication extends Application {
#Override
public Set<Class<?>> getClasses() {
return Collections.singletonSet(MyClass.class);
}
#Override
public Set<Object> getSingletons() {
return Collections.singletonSet(new MyBinder(new MyStateImpl()));
}
}
You can now run your application where MyStateImpl is always injected into MyClass.
Jersey (and JAX-RS in general) allows simple dependency injection as follows:
#Path("/")
public class MyResource {
#Context private Application application;
...
}
Jersey first creates the class, then it binds dependencies to it. Is this a mechanism I can re-use for instances whose lifecycle I control entirely?
For example, consider an interface with some unknown implementations.
public interface MyInterface {
public boolean isHappy();
}
Suppose I have a list of these in one of my provider singletons, for example, an ExceptionMapper. It would be initialized in some subclass of Application.
#Provider
public class MyExceptionMapper implements ExceptionMapper<Exception> {
private List<MyInterface> list;
public ExceptionMapper(List<MyInterface> list) {
this.list = list;
}
#Override
public Response toResponse(Exception e) {
for (MyInterface item : list) {
// Manually bind dependencies here?
if (item.isHappy()) {
return Response.ok("Nope, no errors here. Promise.").build();
}
}
return Response.serverError().build();
}
}
And finally, suppose there's a specific implementation of this interface that needs access to the Application:
public class MyImplementation implements MyInterface {
#Context private Application application; // Can't do this
#Override
public boolean isHappy() {
MyApplication myApp = (MyApplication) application;
return myApp.shouldIgnoreExceptions(); // NullPointerException
}
}
Is there a way to bind contexts for all of the implementations of my interface? Or do I need to find a way to get Jersey to manage all implementations (by making them providers)? Or must I resort to CDI to perform dependency injection?
Note that I'm using Jersey 1.17.1, and I'd like to avoid defining any particular dependency as being part of the interface.
The JAX-RS way is to implement your own ContextResolver for MyInterface. Then you can manage the implementation of the contexts inside the context resolved. Context resolver is provider and is managed by Jersey, but not the MyInterface implementations.