JAX-RS Param Converter- Compile time error using it - rest

This is my param converter
import org.springframework.data.domain.Sort;
public class MyParamConverter implements ParamConverter<Sort> {
#Override
public Sort fromString(String s){
return new Sort(new Sort.Order(Sort.Direction.ASC, "ds"));
}
#Override
public String toString(Sort mo){
return mo.toString();
}
}
this is my paramconverter provider
#Provider
public class MyParamConverterProvider implements ParamConverterProvider {
#Override
public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType, Annotation[] annotations) {
if(rawType.equals(Sort.class)){
return (ParamConverter<T>) new MyParamConverter();
}
return null;
}
I am trying to use in my API as
#GET
#Path("/")
Response read(#QueryParam("sort") Sort order);
I am expecting the jax to map string that I pass in my url e.g. &sort="asc" to Sort object. But I am getting an compile time error that have a registered implementation of paramconverter provider. I need to find a way when I pass a query param as &sort="somethung" it gets convert to SORT automatically either by using custom annotation or by using Param Converter.

with reference to your comment, try registering your provider like:
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
#Override
public Set<Class<?>> getClasses() {
final Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(MyParamConverterProvider.class);
return classes;
}
}
or, if you are using Jersey
#ApplicationPath("/")
public class MyApplication extends ResourceConfig {
public MyApplication() {
packages("my.package");
// or without package scanning
register(MyParamConverterProvider.class);
}
}

Related

How to change base url endpoint for errai jaxrs proxy?

I' need to call different endpoint located on different server, i try to change value of base url of my rest services.
but i found only this method
RestClient.create(MyService.class, otherServiceBaseUrl,
myCallback,
200).doStaf() ;
Any suggestion to more elegant way for setup the base url for all services in my MyService class ?
I found this solution.
I create a abstract class DinamicCaller.
public abstract class DinamicCaller<T> {
public T call() {
T call = getCaller().call();
((AbstractJaxrsProxy) call).setBaseUrl(getBaseUrl());
return call;
}
public T call(RemoteCallback<?> callback) {
T call = getCaller().call(callback);
((AbstractJaxrsProxy) call).setBaseUrl(getBaseUrl());
return call;
}
public T call(RemoteCallback<?> callback, ErrorCallback<?> errorCallback) {
T call = getCaller().call(callback, errorCallback);
((AbstractJaxrsProxy) call).setBaseUrl(getBaseUrl());
return call;
}
protected abstract Caller<T> getCaller();
protected abstract String getBaseUrl();
}
I create a Concrete Class
public class CallerCORSNegoziService extends DinamicCaller<CORSNegoziService> {
#Inject
NegozioManager negozioManager;
#Inject
Caller<CORSNegoziService> caller;
#Override
protected Caller<CORSNegoziService> getCaller() {
return caller;
}
#Override
protected String getBaseUrl() {
return negozioManager.getNegozio().getUrl();
}
}
On my class I inject the concrete class
#Inject
CallerCORSNegoziService service;
And I use it
#UiHandler("testButton")
public void testButtonClick(ClickEvent event) {
service.call(testCallback, testCallback).findAllNegozi();
}
Is ugly but work.

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
....
}

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.

Spring Java config message convertor priority

I have defined two convertors like this using Spring Java config. I always get a XML response unless I specified the 'Accept=applicaiton/json' in the HTTP header. Is there a way to set the default convertor to be JSON instead of XML convertor.
#EnableWebMvc
#Configuration
#ComponentScan(basePackages = {"foo.bar"})
public class WebMvcConfig extends WebMvcConfigurerAdapter {
...
#Bean
public MappingJackson2HttpMessageConverter jsonConverter() {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
ObjectMapper objectMapper = new ObjectMapper();
jsonConverter.setObjectMapper(objectMapper);
return jsonConverter;
}
#Bean
public MappingJackson2XmlHttpMessageConverter xmlConverter() {
MappingJackson2XmlHttpMessageConverter xmlConverter = new MappingJackson2XmlHttpMessageConverter();
return xmlConverter;
}
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jsonConverter());
converters.add(xmlConverter());
super.configureMessageConverters(converters);
}
Here is my controller.
#RequestMapping(value = "/product")
public
#ResponseBody
BSONObject getProducts(#RequestParam String ids,
#RequestParam(required = false) String types) {
List<BSONObject> products = commonDataService.getData(ids, types);
return products;
}
Try the following configuration, it sets up the default Content negotiation strategy(based on article here):
#Configuration
#EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
#Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.defaultContentType(MediaType.APPLICATION_JSON);
}
}
Another option will be to provide other ways of specifying the content format, if Accept header is not feasible, an option could be to specify an extension /myuri/sample.json which would be returned as a json.

How to use provider in Errai IOC?

I have a problem with #IocProvider (), annotation does not work.
The code is very similar to https://docs.jboss.org/author/display/ERRAI/Container+Wiring
public interface Test {
String getGreeting();
}
#ApplicationScoped
public class TestImpl implements Test {
public String getGreeting() {
return "Hello:)";
}
}
#IOCProvider
#Singleton
public class TestProvider implements Provider<Test> {
#Override
public Test get() {
return new TestImpl();
}
}
Then I want use DI in my broadcast service (errai-bus).
#Service
public class BroadcastService implements MessageCallback {
#Inject
Test test;
#Inject
MessageBus bus;
#Inject
public BroadcastService(MessageBus bus) {
this.bus = bus;
}
public void callback(Message message) {
MessageBuilder.createMessage()
.toSubject("BroadcastReceiver")
.with("BroadcastText", test.getGreeting()).errorsHandledBy(new ErrorCallback() {
#Override
public boolean error(Message message, Throwable throwable) {
return true;
}
}).sendNowWith(bus);
}
}
I get a error:
1) No implementation for com.gwtplatform.samples.basic.server.Test was bound.
while locating com.gwtplatform.samples.basic.server.Test
for field at com.gwtplatform.samples.basic.server.BroadcastService.test(BroadcastService.java:32)
at org.jboss.errai.bus.server.service.ServiceProcessor$1.configure(ServiceProcessor.java:118)
If I change the code to
#Inject
TestImpl test;
It works, but I need the provider. Do you have some idea?
Because you're trying to use #IOCProvider in server-side code. Errai IOC is completely client-side.