CXF #CrossOriginResourceSharing Annotation - rest

I am using CXF/Karaf, and I have many different RESTful resources within multiple packages/classes.
Question: Is there a way to avoid having to write annotations above every resource, such as #CrossOriginResourceSharing?
I would like to be able to put this in one place. Below is an example of how this is currently being used:
#CrossOriginResourceSharing(
allowOrigins = {"http://<ip>:<port>"}
)
#GET
#Path("/rest")
#Produces(MediaType.APPLICATION_JSON)
public String rest();

You can add this to the class instead of on each resource in the class (and I haven't tested this but you could possible create a super class with this annotation and extend it but I'm not sure if CXF will honour it):
#CrossOriginResourceSharing(
allowOrigins = {"http://<ip>:<port>"}
)
public class resourceGroup {
#GET
#Path("/rest")
#Produces(MediaType.APPLICATION_JSON)
public String rest();
}

Related

GET and PUT methods for same route don't work if in separate classes

We're using specific route attributes for all our web api routes.
We want to split up a controller class, so we're moving some update functions out to a separate controller class.
We've subsequently got an odd situation with routing.
The original controller class looked like this:
[RoutePrefix("activities")]
public class ActivitiesController : ApiController
{
...
[Route("{activityId:int:min(1)}"), HttpPut]
public void Put(int activityId, [FromBody] NewActivity value) {}
[Route("{activityId:int:min(1)}"), HttpGet]
public dynamic Get(int activityId) {}
...
}
And we then split out the updates, so we end up with this:
[RoutePrefix("activities")]
public class ActivitiesUpdateController : ApiController
{
...
[Route("{activityId:int:min(1)}"), HttpPut]
public void Put(int activityId, [FromBody] NewActivity value) {}
...
}
[RoutePrefix("activities")]
public class ActivitiesController : ApiController
{
...
[Route("{activityId:int:min(1)}"), HttpGet]
public dynamic Get(int activityId) {}
...
}
If we then try to call either endpoint:
- PUT activities/42
- GET activities/42
We get the error:
Multiple controller types were found that match the URL. This can happen if attribute routes on multiple controllers match the requested URL.
The request has found the following matching controller types:
API.Controllers.ActivitiesUpdateController
API.Controllers.ActivitiesController
If both endpoints are in the same class (either the new one or the old), everything works correctly.
Different classes raises the error.
If I dump out the endpoints using ApiExplorer, both end points are where they should be and are not repeated in the other class, so there's no obvious duplication.
I've tried renaming functions, explicit routes (i.e. ~/activities/:id), adding HttpGet & HttpPut doesn't seem to make a difference.
Is this some weird "feature" where the same endpoint with different methods have to be in the same class?
It makes no sense.
Not to worry, I came across this after I posted - don't know how I missed it before:
Multiple controllers with same URL routes but different HTTP methods

Resource not exported up in OSGi container

I'm trying to expose a REST service through OSGi (using Apache Felix). I'm using the osgi-jax-rs-connector to publish the resource. Here is the resource interface:
#Path("/bingo")
public interface BingoService {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/lottery")
List<Integer> getLottery();
}
The implementation uses DS annotation to obtain reference to a provided service in container:
#Component(
immediate = true,
service = BingoService.class,
properties = "jersey.properties")
public class Bingo implements BingoService {
#Reference
private RandomNumberGenerator rng;
#Activate
public void activateBingo() {
System.out.println("Bingo Service activated using " +
rng.getClass().getSimpleName());
}
#Override
public List<Integer> getLottery() {
List<Integer> result = new ArrayList<>();
for (int i = 5; i > 0; i--) {
result.add(rng.nextInt());
}
return result;
}
}
jersey.properties simply contains this line
service.exported.interfaces=*
When I deploy the bundle it starts and register the service correctly. But if I go to http://localhost:8181/services/bingo/lottery I get 404.
Could someone point me to the issue or give me some advice on where to look?
On reading the documentation for OSGi - JAX-RS Connector, it expects to find the annotations #Path or #Provider on the service instance object. You have placed them instead on an interface implemented by the component.
I'm not sure what the purpose of the BingoService interface is. This is not required for JAX-RS services. Normally you would register the resource class using its own type (e.g. service=Bingo.class) or simply java.lang.Object.

Web Api 2 Inheritance No route providing a controller name was found to match request URI

Basically I cannot get my Web Api 2 application to work.
First of all here are my requirements.
In my application I am creating a dozen of controllers ( ProductController, ItemController, SalesController...etc). There are 2 actions which are absolutely common in all my controllers:
FetchData, PostData
(Each controller then may implement a number of other methods which are sepcific to its business domain )
Instead of repeating these actions in every controllers like:
public class ProductController:ApiController{
[HttpPost]
public MyReturnJson FetchData( MyJsonInput Input){
....
return myJsonResult;
}
}
public class SalesController:ApiController{
[HttpPost]
public MyReturnJson FetchData( MyJsonInput Input){
....
return myJsonResult;
}
}
I decided to create a base controller MyBaseController:
public class MyBaseController : ApiController{
[HttpPost]
public MyReturnJson FetchData( MyJsonInput Input){
....
return myJsonResult;
}
}
with the 2 methods so every other controller would inherit them (It saves me from repeating them in every controller). The common base class has been defined and implemented in a separate assembly which is then referenced in my web project.
Then in my javascript client (using breeze) I call a specific controller like
breeze.EntityQuery.from('FetchData')
where my serviceName is 'my_api/product/'
(in the WebApiConfig, the routing table has been defined like:
config.Routes.MapHttpRoute(
name: "my_api",
routeTemplate: "my_api/{controller}/{action}"
);
But when the javascript code is executed I get the error message:
No route providing a controller name was found to match request URI
http://localhost:xxxxx/my_api/product/FetchData
If I don't use a common base class but instead repeat this method (FetchData) in every class (basically ProductController inherits directly from ApiController and not from MyBaseController) every thing works fine and my method is hit. I thing there is a problem with the inheritance scheme. Maybe there is something I don't get (first time using Web Api 2) or some constraints (routing, configuration...) I do not respect. Right now I am stuck and I would appreciate any suggestion which might point me to the right direction. Is inheritance allowed in Web Api 2?
I am not sure why your code is not working. But in the next link (http://www.asp.net/web-api/overview/releases/whats-new-in-aspnet-web-api-22#ARI) you can see an example of inheritance using attribute routing.
This is the code example:
public class BaseController : ApiController
{
[Route("{id:int}")]
public string Get(int id)
{
return "Success:" + id;
}
}
[RoutePrefix("api/values")]
public class ValuesController : BaseController
{
}
config.MapHttpAttributeRoutes(new CustomDirectRouteProvider());
public class CustomDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(HttpActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes<IDirectRouteFactory>
(inherit: true);
}
}
I hope that it helps.

How to add structural links to Jersey/Moxy/JAXB XML without altering the model

I mean "structural links" in the HATEOAS/hypermedia API sense. The more general question is how to augment the generated XML with data that depends on both the entity being marshalled, and also on the environment (in this case, at least the absolute URL).
I'm using Jersey 2.9 with Moxy 2.5 as the JAXB provider.
From this model:
package testing;
import java.util.ArrayList;
import java.util.List;
public class Planet {
private int id = 1;
private String name = "test";
private double radius = 3.0;
private String href;
private List<Moon> moons = new ArrayList<Moon>(0);
public void addMoon(Moon moon) {
moons.add(moon);
}
}
...plus Moon class
I want to get something like this XML (and the equivalent JSON):
<planet href="http://mytestserver/rest/planets/test">
<name>test</name>
<radius>3.0</radius>
<moons>
<moon href="http://mytestserver/rest/moons/moon1">
<name>moon1</name>
</moon>
<moon href="http://mytestserver/rest/moons/moon2">
<name>moon2</name>
</moon>
</moons>
</planet>
The model has no "href" field, nor can one be added. Ideally I could use UriBuilder to grab these paths straight from the resource classes.
So far I've come up with several possiblities. Can I ask you to consider which (if any) has the most legs, and then how you would work around the shortcomings of that method?
1. Augment the model with AspectJ (or Javassist).
And then use the existing declarative linking mechanisms in Jersey, all of which rely on there being a field in the model to receive the generated links. This obviously won't work if you don't have AspectJ in your build process and/or balk at exotic techniques like byte code manipulation.
2. Post-process the generated XML and JSON
For example, in a MessageBodyWriter:
ContextResolver<JAXBContext> resolver = providers.getContextResolver(JAXBContext.class, mediaType);
JAXBContext context = resolver.getContext(type);
Marshaller m = context.createMarshaller();
<--- here, marshall to e.g. a DOM then transform that
<--- then manipulate the JSON structures
I have absolutely no idea how to do any of that, hence the lack of code. There may be other ways to hook into the XML generation process, but as far as I can see none of Jersey's or JAXB's event handlers or interceptors actually allow you to manipulate the generated XML/JSON.
3. Use a Moxy XMLTransformationMapping
For example:
XML binding:
<java-type name="Planet" xml-customizer="testing.HrefCustomizer">
Customizer:
public class HrefCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
XMLTransformationMapping xtm = new XMLTransformationMapping();
xtm.addFieldTransformer("#href", new HrefWriter());
descriptor.addMapping(xtm);
}
}
Transformer:
public class HrefWriter implements FieldTransformer {
#Override
public Object buildFieldValue(Object instance, String fieldName,
Session session) {
return "href"; // constant value just for proof-of-concept
}
#Override
public void initialize(AbstractTransformationMapping mapping) {
// TODO Auto-generated method stub
}
}
I have two problems with this approach:
It was so hard to find any documentation on it that I wonder if it is in fact unsupported usage.
I can't see how the transformer is going to get a UriBuilder to work with. At minimum it would need the root URL of the rest service.
4. Slightly different Moxy xml-transform approach
If we decide we can't provide the transformer with any meaningful context at instantiation time, the customizer is adding no value and we can simplify the above to just this:
<java-type name="Planet">
<xml-root-element/>
<java-attributes>
<xml-transformation java-attribute="name">
<xml-write-transformer transformer-class="testing.HrefWriter" xml-path="#href"/>
</xml-transformation>
<xml-element java-attribute="name"/>
With the slight oddity that we are hanging the transformer off another field ("name", in this example).
5. ?????
Or, I'm completely barking up the wrong tree. Help!!
AspectJ approach
Synopsis
Use AspectJ to add a field to the model classes (called "href" in this example)
Add the Jersey #InjectLink annotation to that field
Jersey will then populate the field with the right URL as defined by the resource class
Specify the marshaling of the href field using an external mapping file.
You could also specify the marshaling of href by adding JAXB annotations to it via the same AspectJ intertype declaration mechanism.
Example code
These are the most informative bits. See http://lagod.id.au/blog/?p=494 for the full example.
The aspect
package testing;
import org.glassfish.jersey.linking.InjectLink;
import org.glassfish.jersey.linking.Binding;
public aspect HrefInjector {
private String Planet.href;
declare #field : * Planet.href : #InjectLink(
resource=Services.class,
style=InjectLink.Style.ABSOLUTE
) ;
private String Moon.href;
declare #field : * Moon.href : #InjectLink(
resource=Services.class,
method="moon",
bindings={#Binding(
name="moonid", value="${instance.name}"
)},
style=InjectLink.Style.ABSOLUTE
) ;
}
Model classes
POJOs with no REST-specific cruft. See Jersey + Moxy + JAXB - how to marshal XML without annotations.
package testing;
import java.util.ArrayList;
import java.util.List;
public class Planet {
private int id = 1;
private String name = "test";
private double radius = 3.0;
private List<Moon> moons = new ArrayList<Moon>(0);
public void addMoon(Moon moon) {
moons.add(moon);
}
}
package testing;
public class Moon {
private String name;
// No-arg constructor is a requirement of JAXB
public Moon() {
}
public Moon(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
Resource class
This is a standard JAX-RS resource class. For demo purposes, we're just returning freshly instantiated model instances.
package testing;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
#Path("/services")
#Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public class Services {
private Planet initPlanet() {
Planet p = new Planet();
p.addMoon(new Moon("moon1"));
p.addMoon(new Moon("moon2"));
return p;
}
#GET
public Planet planet () {
return initPlanet();
}
#GET #Path("/moons/{moonid}")
public Moon moon (#PathParam("moonid") String name) {
return new Moon(name);
}
}
Moxy mapping file
Note that you can choose for any given type whether or not you want to actually marshal the href field. In fact, by using multiple mapping files, you can include the href field in some representations and not in others.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="testing"
xml-mapping-metadata-complete="true"
xml-accessor-type="NONE">
<java-types>
<java-type name="Planet">
<xml-root-element/>
<java-attributes>
<xml-attribute java-attribute="href"/>
<xml-element java-attribute="name"/>
<xml-element java-attribute="radius"/>
<xml-element java-attribute="moons" name="moon">
<xml-element-wrapper name="moons"/>
</xml-element>
</java-attributes>
</java-type>
<java-type name="Moon">
<xml-root-element/>
<java-attributes>
<xml-attribute java-attribute="href"/>
<xml-element java-attribute="name"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
Sample output
Ta-dah! Structural links derived automatically from the JAX-RS resource class without altering model source code. Because we're using Moxy, we also get JSON for free.
<planet href="http://localhost:8080/reststructlinks/rest/services">
<name>test</name>
<radius>3.0</radius>
<moons>
<moon href="http://localhost:8080/reststructlinks/rest/services/moons/moon1">
<name>moon1</name>
</moon>
<moon href="http://localhost:8080/reststructlinks/rest/services/moons/moon2">
<name>moon2</name>
</moon>
</moons>
</planet>

JAX-RS #PathParam to inject in class member variable?

I want to do something like this:
#Stateless
#Path("/sensors/{sensorid}/version")
#Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
#Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
public class SensorVersionRestView extends VersionRestView{
#PathParam("sensorid")
private String sensorid;
#GET
#Path("count")
// so the complete path is i.e.
// domain.com/rs/sensors/111211/version/count
public void getCount() {
// do something with the sensorId....
}
}
But the only thing I get is null on runtime (I use Glassfish v3 with Jersey). The compiler and eclipse never mentions a problem with the #PathParam at the member class variable.
What's wrong with my construct?
The main problem is, why I doesn't want to use the whole path on each method in this class, that there exists another class which handles some rest operations on the sensor layer (deomain.com/rs/sensors/count i.e.)
I believe you need to change it to this:
#Stateless
#Path("/sensors/{sensorid}/version")
public class SensorVersionRestView extends VersionRestView {
#GET
#Path("count")
#Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
#Produces({MediaType.APPLICATION_XML, MediaType.TEXT_XML})
// domain.com/rs/sensors/111211/version/count
public void getCount(#PathParam("sensorid") String sensorid) {
// do something with the sensorId....
}
}
Because injection occurs at object
creation time, use of this annotation
on resource class fields and bean
properties is only supported for the
default per-request resource class
lifecycle. Resource classes using
other lifecycles should only use this
annotation on resource method
parameters. - JSR-311 Javadocs
You should be able to annotate fields with #PathParam as long as the resource class lifecyle is per-request. By default the life-cycle of root resource classes is per-request.
EDIT: I don't think you can achieve this using EJBs. If you remove the #Stateless annotation, it should work.