Parent/Child resource classes - annotations don't work in parent class - java

I don't have any specific examples in front of me right now, but I've had this issue in the past.
When I have a resource that extends another class and utilizes annotations, can the base class have annotations that are read as if they're part of the child class? I've tried to do this in some scenarios and it doesn't ever seem to work. Is there some way to make this possible? Is this a scope issue with no #Path being defined for the base class?
#Path("/workflow")
#Consumes({MediaType.APPLICATION_JSON})
#Produces({MediaType.APPLICATION_JSON})
public class WorkflowResource extends BaseWorkflowResource {
#GET
#Path("/getAllActive")
public Collection<WorkflowEntity> getActive () {
return MyClass.getAllActive();
}
}
//THIS CALL WON'T BE AVAILABLE
public class BaseWorkflowResource {
#GET
#Path("/getMyString")
public String getActiveString () {
return "my string";
}
}

This method
public Collection<WorkflowEntity> getActive()
will override this method
public String getActive()
This is not a matter of JAX-RS but of plain Java. Both methods have the same signature (name, parameters).
Try using different method signatures in parent and child class.

Related

Is it safe to use String as a return type of a bean in spring?

#Configuration
public class Product {
#Bean("xyz")
public String getMethod() {
return "abc";
}
}
#Component
public class Test {
String b;
Test(String xyz) {
this.b = xyz;
}
}
Is this any harm with this approach? I am trying to make change in the existing code where I am replacing the #Value with the getter as the method parameter. As I don't want to change the structure of the existing code I am trying to inject the method as bean as a replacement to #Value.
I suggest you to keep the #Value annotation instead of the whole #Bean configurations.
Why?
What if the getMethod()'s returned value needs to be changed very often? Everytime when you're changing something in the Product class, during build time it needs to be recompiled. What happens if the project is getting bigger and you're using this approach? It leads to longer build time and the more important thing is that this solution is not intuitive and it's hard to keep it clean. Don't think about complex solutions only to make the code look fancy. When you need to inject String values, the easiest approach is to create properties files (which won't get recompiled) and use the #Value annotation.
Now, if you want to add new methods without changing the structure of the existing code there are some patterns which you can apply like decorator pattern.
The main idea is simple: you're creating a decorator class which has an object of the type you need.
The easiest example (which you'll find everywhere on the internet) is the classic Shape example:
public interface Shape {
String someMethod();
}
#Component
public class CustomShape implements Shape { //implement the method here }
And here is the decorator:
public interface ShapeDecorator {
String someMethodExtended();
void someExtraMethod();
}
#Component
public class CustomShapeDecorator implements ShapeDecorator{
#Autowired
// #Qualifier - optional (only if you have more Shape implementations)
private Shape shape;
// now you can either:
// 1. provide new methods
#Override
public void someExtraMethod(){
System.out.println("Hello world!");
}
// 2. or you can EXTEND the Shape's "someMethod()" implementation
#Override
public String someMethodExtended(){
String oldString = this.shape.someMethod();
return oldString + " EXTENDED";
}
}

webTarget.request returns type not acceptable by builder.method

I am trying to unittest an API REST function.
builder = webTarget.request();
returns builder of the type
javax.ws.rs.client.Invocation.Builder
But if I take that builder and call builder.method("POST", entity) on it, the method called looks thus:
public Response method(final String name, final Entity<?> entity) throws ProcessingException {
requestContext.setMethod(name);
storeEntity(entity);
return new JerseyInvocation(this).invoke();
}
And the last line uses as "this" different builder:
org.glassfish.jersey.client.JerseyInvocation.Builder
And the run fails on that line.
I am looking at it and feel me crazy: How could it be, that the function is called as a member of one class, but when "this" is used in that method, absolutely different class is used?
Both Invocation and Invocation.Builder are interfaces. The WebTarget.request() contract is to return Invocation.Builder. These are all interfaces we are talking about here; WebTarget, Invocation, Invocation.Builder. This is contract design by the JAX-RS specification. It is up the JAX-RS implementation to implement these interfaces. Jersey implementation are JerseyWebTarget, JerseyInvocation, and JerseyInvociation.Builder, respectively.
It's the same if I created something like this
public interface Model {}
public interface Service {
Model getModel();
}
public ModelImpl implements Model {}
public class ServiceImpl implements Service {
#Override
public Model getModel() {
return new ModelImpl();
}
}
There's nothing special goin on here. The Service contract says that the getModel() method returns a Model, which is an interface, the actual return value will be of type ModelImpl, the implementation. Polymorphism in the works.

Spring Data Rest ResourceProcessor for Projection Exception

I have created the following Projection
#Projection(name = "select", types = {Organisation.class})
public interface OrganisationSelectProjection {
Long getId();
String getName();
}
Which I want to basically use in a "Select" component so I need the least data possible. So I also wanted to remove all the links with a ResourceProcessor, so I created this:
#Bean
public ResourceProcessor<Resource<OrganisationSelectProjection>> organisationProcessor() {
return resource -> {
resource.removeLinks();
return resource;
};
}
However, it looks like this breaks the entire API since whatever endpoint I hit I get the following exception message org.springframework.hateoas.PagedResources cannot be cast to org.springframework.hateoas.Resource
Any idea what I have doen wrong?
If you'd like to keep anonymous class in place, using ResourceSupport instead of Resource can resolve the issue.
#Bean
public ResourceProcessor<ResourceSupport> organisationProcessor() {
return resource -> {
resource.removeLinks();
return resource;
};
}
But in this case the processor will be used on each and every resource regardless of type of the content (you can check that inside the method body though).
Instead of anonymous descendant of ResourceProcessor you can define it as a stand-alone class:
public class OrganizationResourceProcessor implements ResourceProcessor<Resource<OrganisationSelectProjection>> {
#Override
public Resource<OrganisationSelectProjection> process(Resource<OrganisationSelectProjection> resource) {
resource.removeLinks();
return resource;
}
}
#Bean
public OrganizationResourceProcessor organisationProcessor() {
return new OrganizationResourceProcessor();
}
The issue you expereinced has something to do with type erasure since there is no any type parameters in the anonymous class implementation. Your definition is type-safe but it lacks that type-related data which is used at runtime when determining whether particular ResourceProcessor can process a resource. So spring-data-rest thinks that anonymous organizationProcessor can process PagedResources and feeds it to the processor where ClassCastException happens.
Not everything spring-data-rest puts through ResourceProcessors is a Resource. There can be different descendants of org.springframework.hateoas.ResourceSupport class (like PagedResources in your case) and majority of them are not inherited from Resource.

Where to include #Webresult ,#WebMethod etc

I have created a JaX Webservice through RAD(eclipse), and I am able to use the #WebParam annotation with my function parameter, however I also want to use #webresult etc but Don't know where should i specify them, on google I got interfaces but here i only have class and delegate class.
my class is
public class GetFPDDataClass {
public String GetFPDDataInput(String PolicyNumber)
{
return PolicyNumber;
}
}
and this is my delegate class
#WebService (targetNamespace="fpd", serviceName="GetFPDDataClassService", portName="GetFPDDataClassPort")
public class GetFPDDataClassDelegate{
fpd.GetFPDDataClass _getFPDDataClass = null;
public String GetFPDDataInput (#WebParam(name="PolicyNumber") String PolicyNumber) {
return _getFPDDataClass.GetFPDDataInput(PolicyNumber);
}
public GetFPDDataClassDelegate() {
_getFPDDataClass = new fpd.GetFPDDataClass(); }
}
Both #WebResult and #WebMethod are set on the method level.
#WebResult is used to customize name of the XML element that represents the return value.
#WebMethod is used to mark business methods that are exposed to web service clients. By default all public methods in your class are exposed, if you don't implement web service interface.
Example:
#WebMethod
#WebResult(name="hellomessage")
public String getHello() {
....
}
UPDATE:
If I dont have #WebResult I see the following xml:
<ns2:getHelloResponse>
<return>hello fff</return>
</ns2:getHelloResponse>
with #WebResult:
<ns2:getHelloResponse>
<hellomessage>hello fff</hellomessage>
</ns2:getHelloResponse>

How to register a static class in Jersey?

I have a class of which only static methods are to be accessed via #path annotations and which does not have a public constructor. My simpilified program is:
#Path("")
static class MyStaticClass
{
private MyStaticClass() {...}
#Get #Path("time")
static public String time()
{
return Instant.now().toString();
}
}
Running and calling "time" gives me the following error:
WARNUNG: The following warnings have been detected: WARNING: HK2 service reification failed for [...] with an exception:
MultiException stack 1 of 2
java.lang.NoSuchMethodException: Could not find a suitable constructor in [...] class.
Sorry, according to the JSR, paragraph 3.1.2
Root resource classes are instantiated by the JAX-RS runtime and MUST
have a public constructor for which the JAX-RS runtime can provide all
parameter values. Note that a zero argument constructor is permissible
under this rule.
You can use the Adapter design pattern and create JAX-RS resource (POJO with #Path) which simply delegates to your static class. This would be very easy to understand for those coming behind you.
The #Path annotation is designed to define a resource at the class level. The method to execute isn't controlled by #Path, but by #GET, #POST, #PUT, #HEAD, etc... with #GET as the desired operation in your case.
Your class for the "time" resource should look like this:
#Path("/time")
public class TimeResource {
#GET
public static String time(){
return Instant.now().toString();
}
}
You could theoretically define each function as a static nested class within one "main" class:
public class MyResource{
#Path("/time")
public static final class TimeResource {
#GET
public static String do(){
return Instant.now().toString();
}
}
#Path("/doSomethingElse")
public static final class DoSomethingElseResource {
#GET
public static String do(){
// DO SOMETHING ELSE
}
}
}
Though I don't know if that would work, you'd have to try it. I don't think there's much advantage in having them all in one class like that, though.

Categories

Resources