JAX-RS - MOXy JAXB - ClassCastException when transforming List<List<Object>> to JSON - rest

In my app I'm using MOXy JAXB with JAX-RS (Jersey) on Glassfish server,
I have the following REST webservice:
#Named
#RequestScoped
#Path("/product")
public class ProductService extends BaseServiceFacade<Product, Integer, ProductVO> {
#EJB(mappedName="java:global/myAppEAR/myAppEJB/ProductServiceRest")
ProductServiceRestRemote productServiceRestRemote;
// ...
#GET
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/featuredlists")
public List<List<ProductVO>> featuredlists() {
return productServiceRestRemote.featuredlists();
}
}
When I try to test the REST service accessing:
localhost:8080/atlanteusPortal/rest/product/featuredlists
I get:
java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl cannot be cast to java.lang.Class
at org.eclipse.persistence.jaxb.rs.MOXyJsonProvider.getDomainClass(MOXyJsonProvider.java:267)
If I put a debug breakpoint before the method return I can see that the List<List<ProductVO>> chunkList is populated but it's not transformed into JSON
Can someone point out a solution to send a List<List<Object>> type via JSON using JAX-RS MOXy and Jersey?

I solved the issue using a workaround encapsulating List of Lists inside an object
called ProductListVO:
#XmlRootElement
public class ProductListVO extends BaseVO<String> {
private List<ProductVO> productVOs;
public List<ProductVO> getProductVOs() {
return productVOs;
}
public void setProductVOs(List<ProductVO> productVOs) {
this.productVOs = productVOs;
}
public static ProductListVO buildVO(List<Product> t) {
ProductListVO vo = new ProductListVO();
List<ProductVO> prodVOs = new ArrayList<ProductVO>();
StringBuilder sb = new StringBuilder();
for (Product product : t) {
sb.append(product.getId()).append('-');
prodVOs.add(ProductVO.buildVO(product));
}
vo.setId(sb.substring(0, sb.length() - 1));
vo.setProductVOs(prodVOs);
return vo;
}
}
in Service method:
#GET
#Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
#Path("/featured")
public List<ProductListVO> featuredlists() {
return productServiceRestRemote.featuredLists();
}

Related

Guice module integration issue with REST

Guice module integration issue with REST
I have define one AOP guice based module, but when I tried to integrate with REST code, methodInvocation.proceed retun null.
What might be best way to solve this issue.
Define AOP Guice based module as below
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
#interface NotOnWeekends {}
public class WeekendBlocker implements MethodInterceptor {
public Object invoke(MethodInvocation invocation) throws Throwable {
Calendar today = new GregorianCalendar();
if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) {
throw new IllegalStateException(
invocation.getMethod().getName() + " not allowed on weekends!");
}
return invocation.proceed();
}
}
public class NotOnWeekendsModule extends AbstractModule {
protected void configure() {
bindInterceptor(Matchers.any(), Matchers.annotatedWith(NotOnWeekends.class),
new WeekendBlocker());
}
}
But I tried to Integrate this with my REST API
public class WorkerBean implements Worker {
#Autowired
private WorkerRepository workerRepository;
#Override
#NotOnWeekends
public Collection<Worker> findAll() {
Collection<Worker> workers = workerRepository.findAll();
return workers;
}
#RestController
public class WorkerController {
#RequestMapping(
value = "/api/workers",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Collection<Worker>> getWorkers() {
Worker worker = Guice.createInjector(new NotOnWeekendsModule()).getInstance(Worker.class);
Collection<Worker> worker = worker.findAll(); // return null
....
}

Manually add providers for jaxb in a resteasy application

I have a rest application where I am using resteasy and jaxb to produce json output
#GET
#Produces({MediaType.APPLICATION_JSON})
#Path("/data")
public MyResponse getData {
return new MyResponse("my response"); // Just stubbing this
}
#XmlRootElement(name = "response")
#JsonInclude(Include.NON_NULL)
public class MyResponse {
private String data;
public MyResponse(String data) {
this.data = data;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
I am not using the web.xml but creating a RestApplication which extends Application and overriding the getSingletons and getClasses method.
Now I am not sure which jaxb provider classes I need to add to make the above working, I mean to do the json serialization.
I get the following error
Could not find MessageBodyWriter for response object of type:MyResponse of media type: application/json
Could you let me know which classes I need to add manually(the providers) to make this work?

Rest api how to get parameters?

I'm new to rest api.
I need to make an api that takes a string as parameter and then return boolean.
Now my question is how to i pass that string to my api, and then get the string inside my api?
Here's one example that takes a string in parameter and has a default value if the query parameter is not provided:
#Path("business/department/")
public interface DepartmentService {
#GET
#Path("/cs/availability/chat")
#Produces(MediaType.APPLICATION_JSON)
boolean getCustomerServiceAvailability(#QueryParam("type") #DefaultValue("chat") String type);
}
and the implementation class can be anything that implements your interface. In this example, it's a stateless EJB
#Stateless
public class DepartmentServiceImpl implements DepartmentService {
#Context
private HttpServletRequest request;
private static final Logger LOGGER = Logger.getLogger(DepartmentServiceImpl.class.getName());
#Override
public boolean getCustomerServiceAvailability(String scheduleType) {
RequestInfo reqInfo = new RequestInfo(request, this.getClass(), "getCustomerServiceAvailability");
boolean available;
try {
available = CallBusinessService(scheduleType);
} catch (Exception e) {
LOGGER.log(Level.SEVERE, e.getLocalizedMessage());
throw new ServiceException();
} finally {
reqInfo.logExecutionTime();
}
}
}

Problems when using EntityFilteringFeature and SelectableEntityFilteringFeature with Jersey 2

I'm new to Jersey 2 and JAX-RS, so probably I'm missing something.
What I'm trying to do is a test program to define a coding style in rest services developing.
The test was written in JAVA and uses JERSEY 2.22.2, JDK 1.8.31, MOXY AS JSON Provider.
I defined a Resource with GET methods to support LIST/DETAIL. Due to the size of my POJO, I used some filters and everything was fine.
// 1) First of all I defined the annotation.
#Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
#Retention(RetentionPolicy.RUNTIME)
#Documented
#EntityFiltering
public #interface MyDetailView {
public static class Factory extends AnnotationLiteral<MyDetailView>
implements MyDetailView {
private Factory() {
}
public static MyDetailView get() {
return new Factory();
}
}
// 2) Once defined the annotation, I used to
// programmaticaly exclude the list of subItems in the response...
#XmlRootElement
public class MyPojo {
...
//*** THIS SHOULD BE FILTERED IF THE ANNOTATION IS NOT SPECIFIED IN THE RESPONSE ***
#MyDetailView
private List<SubItem> subItems = new ArrayList<SubItem>();
public List<SubItem> getSubItems() {
return subItems;
}
public void setSubItems(List<SubItem> subItems) {
this.subItems = subItems;
}
}
// 3) I registered the EntityFilteringFeature
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
....
register(EntityFilteringFeature.class);
}
// 4) Finally, I wrote the code to include/exclude the subItems
/*
The Resource class has getCollection() and getItem() methods...
getCollection() adds the annotation only if filterStyle="detail"
getItem() always add the annotation
*/
#Path(....)
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class MyResource extends SecuredResource {
//filterStyle -> "detail" means MyDetailAnnotation
#GET
public Response getCollection(
#QueryParam("filterStyle") String filterStyle,
#Context UriInfo uriInfo) {
//THIS CODE AFFECTS THE RESPONSE
boolean detailedResponse = "detail".equals(filterStyle);
Annotation[] responseAnnotations = detailedResponse
? new Annotation[0]
: new Annotation[]{MyDetailView.Factory.get()};
//pojo collection...
MyPagedCollection myCollection = new MyPagedCollection();
//.....
ResponseBuilder builder = Response.ok();
return builder.entity(myCollection, responseAnnotations).build();
}
#GET
#Path("/{id}")
public Response getItem(#PathParam("{id}") String idS, #Context UriInfo uriInfo) {
MyPOJO pojo = ...
Annotation[] responseAnnotations = new Annotation[]{MyDetailView.Factory.get()};
return Response.ok().entity(pojo, responseAnnotations).build();
}
}
After the first test, I tried to use the SelectableEntityFilteringFeature to allow the client to ask for specific fields in the detail, so I changed the ApplicationConfig
public class ApplicationConfig extends ResourceConfig {
public ApplicationConfig() {
....
register(EntityFilteringFeature.class);
register(SelectableEntityFilteringFeature.class);
property(SelectableEntityFilteringFeature.QUERY_PARAM_NAME, "fields");
}
and I've add the "fields" QueryParam to the Resource getItem() method...
#GET
#Path("/{id}")
public Response getDetail(#PathParam({id}) String id,
#QueryParam("fields") String fields,
#Context UriInfo uriInfo) {
....
But as long as I registered the SelectableEntityFilteringFeature class, the EntityFilteringFeature class stopped working. I tried to add "fields" parameter to one of the Resource methods, it worked perfectly. But the MyDetailAnnotation was completely useless.
I tried to register it using a DynamicFeature
public class MyDynamicFeature implements DynamicFeature {
#Override
public void configure(ResourceInfo resourceInfo, FeatureContext context) {
if ("MyResource".equals(resourceInfo.getResourceClass().getSimpleName())
&& "getItem".equals(resourceInfo.getResourceMethod().getName())) {
//*** IS THE CORRECT WAY TO BIND A FEATURE TO A METHOD? ***
//
context.register(SelectableEntityFilteringFeature.class);
context.property(SelectableEntityFilteringFeature.QUERY_PARAM_NAME, "fields");
}
}
Now the questions:
1) Why registering both the SelectableEntityFilteringFeature feature breaks the EntityFilteringFeature?
2) What is the correct way to bind a feature to a method with the DynamicFeature interface?
Thanks in advance.
This is my first post to Stack Overflow, I hope it was written complaining the rules.
Short answer: you can't. It appears to be a bug as of 2.25.1 and up to 2.26(that I tested with). https://github.com/jersey/jersey/issues/3523
SelectableEntityFilteringFeature implictily registers EntityFilteringFeature (As mentioned here). So I don't see a need to add this.
Since you need Annotation based filtering, you can exclude registering SelectableEntityFilteringFeature.
You can just do,
// Set entity-filtering scope via configuration.
.property(EntityFilteringFeature.ENTITY_FILTERING_SCOPE, new Annotation[] {MyDetailView.Factory.get()})
// Register the EntityFilteringFeature.
.register(EntityFilteringFeature.class)
// Further configuration of ResourceConfig.
You can refer to this example for usage and this example for registering the filter.
So you can remove SelectableEntityFilteringFeature and try just the above mentioned way to register it.

CXF REST: How can I retrieve the POJO object from the message in an interceptor before it gets marshal'd?

We have implemented a REST API in CXF. My goal is to be able to define custom annotations on a POJO and process them in a CXF interceptor before they get marshal'd. I believe I have all the information I need to be able to do this except for retrieving the actual object in the interceptor. My code looks like this:
Resource class
#Path("/mypath")
public class MyResource {
#GET
public MyObject getObject() {
MyObject o = new MyObject();
...
return o;
}
}
MyObject
public class MyObject {
private String x;
#MyAnnotation
public String getX() {
return x;
}
public String setX(x) {
this.x = x;
}
}
Interceptor
public class MyInterceptor extends AbstractPhaseInterceptor<Message> {
public VersionOutInterceptor() {
super(Phase.POST_LOGICAL);
}
public final void handleMessage(Message message) {
// 1. STUCK -- get object from the message
// 2. parse annotations and manipulate the object
// 3. put the object back on the message for serialization
}
}
How do I get the object from the message, manipulate it based on the annotations, and put it back on the message?
I have similar requirement and this is how I could do it
for In Interceptor I have used PRE_INVOKE Phase and for Out Interceptor PRE_LOGICAL Phase.
This code shows only logging but you can change the object if needed by Usecase.
code as below will fetch you the object you are looking for
#Override
public void handleMessage(Message message) throws Fault {
MessageContentsList objs = MessageContentsList.getContentsList(message);
if (objs != null && objs.size() == 1) {
Object responseObj = objs.get(0);
DomainPOJO do= (DomainPOJO)responseObj;
_logger.info(do.toString());
}
}