spring can't instantiate UriInfo in rest service - rest

I try to use UriInfo to get the list of request parameters, here is my code :
#RestController public class MyController {
#RequestMapping(value = "/documents", produces = MediaType.APPLICATION_JSON_VALUE, method = RequestMethod.GET)
public Object getDocuments( #Context UriInfo uriInfo,
#RequestParam(value = "sta", required = false) String param1, #RequestParam(value = "sta2", required = false) String param2){
MultivaluedMap<String, String> queryParamList = uriInfo.getQueryParameters();
}
this code cause this exception :
org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.ws.rs.core.UriInfo]: Specified class is an interface
thanks for help

It's because UriInfo isn't a Spring MVC object. It is a JAX-RS object and you are not using JAX-RS, you're using Spring MVC. With Spring MVC, if you just want the parameter map, you can just inject it with #RequestParam
public Object getDocuments(#RequestParam MultiValueMap<String, String> requestParams)
Note, the MultiValueMap is a Spring class, it's not the JAX-RS MultivaluedMap.
See also:
Spring MVC - How to get all request params in a map in Spring controller?

Related

Microprofile java.lang.ClassCastException: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream incompatible

I'm using microprofile 3.2 to call out to a rest webservice that returns a java bean in a Response entity. When I try to extract the bean from the response though I get a
java.lang.ClassCastException: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream incompatible with <class>
error.
E.g.
My bean:
public class MyBean {
private int id;
public int getId() { return id; }
public void setId(final int id) { this.id = id; }
}
REST WS api interface:
#GET
#Path("/{id}")
Response getBean(#PathParam("id") Integer id);
REST implementation class:
public Response getBean(final Integer id) {
MyBean myBean = new Service().getBean(id);
return Response.ok(myBean).build();
}
RestClient:
IBeanResource beanResource =
RestClientBuilder.newBuilder().baseUri(apiURI).build(IBeanResource.class);
Response beanResponse = beanResource.getBean(100);
if (beanResponse.getStatus() == Response.Status.OK.getStatusCode()) {
MyBean bean = (MyBean) beanResponse.getEntity();
}
Error fires on line
MyBean bean = (MyBean) beanResponse.getEntity();
Has anyone seen this before? The documentation isn't great.
Yes that would be the expected behavior. If you inspect the value of beanResponse in debug you will see the Response is of type InboundJaxrsResonse and entity is nothing but of type HttpUrlConnector. Which is why when you try to cast it to your custom bean class it throws ClassCastException. You can try any of the following approach:
you could instead do as below
String jsonString = beanResponse.readEntity(String.class);
The above will give you the JSON response as String and then you may convert it to your respective class using libraries such as gson or jackson of your choice.
In your REST WS api interface instead of returning Response return your model MyBean. As per the Microprofile rest Client spec it states the implementation of Microprofile Rest client must provide a built-in JSON-P entity provider and if it supports JSON-B then it must provide JSON-B entity provider.
microprofile-rest-client-spec-2.0
Thanks for the reply. I'll take a look at the spec again for returning models. I like the idea of capturing the response rather than the model so I have any header or status information too e.g. how would a 404 be handed if the resource could not be found?
I was able to get around this by reading the InputStream and using jsonb to bind to the bean
InputStream is = (InputStream) beanResponse.getEntity();
return jsonb.fromJson(is, MyBean.class);

How to get a JSF application scoped bean from webservice?

I have a jsf 2.0 application without Spring and I have implemented a cache as application scope which should be accessed from a Rest service. Now I would like to call the rest webservice which should check the cache, but when I want access it, it is always null.
I tried already Accessing FacesContext from Web Service and this one https://www.mkyong.com/jsf2/how-to-get-servletcontext-in-jsf-2/ , but it doesn't work for me.
#ManagedBean(eager=true)
#ApplicationScoped
public class CacheController implements Serializable{
private static final long serialVersionUID = 123L;
private Map<String, Cache> map = new HashMap<String, Cache>();
public Map<String, Cache> getMap() {
return map;
}
public void setMap(Map<String, Cache> map) {
this.map = map;
}
}
#Path("/service")
public class RestService {
#POST
#Path("anlieferung/kennzahlen")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public String getValueFromCache(String item) throws JSONException, ParseException {
//is always null
CacheController cacheController= (CacheController) getServletContext().getAttribute("cacheController");
//is always null
FacesContext context = FacesContext.getCurrentInstance();
Application application = context.getApplication();
CacheController cacheBean = application.evaluateExpressionGet(context, "#{cacheController}", CacheController.class);
//doSomeStuff and check if the item is in the Cache (CacheController.getMap())
}
}
I have initialised the cache before over the jsf application and it works. Now I would expected that I get the Cache Object through the FacesContent or ServletContext, but it is always null. Do I need to create something like a ServletListener? Can somebody give me an example? Thank you

Unit Testing Rest Services with Spring Boot and JUnit

I have a basic SpringBoot app. using Spring Initializer, JPA, embedded Tomcat, Thymeleaf template engine, and package as an executable JAR file. I've defined this Rest method to get a User
#GetMapping(path = "/api/users/{id}",
consumes = "application/json",
produces = "application/json")
public ResponseEntity<User> getUser
(HttpServletRequest request,
#PathVariable long id) {
User user = checkAccess(request, id);
return ResponseEntity.ok(user);
}
I've created this Junit to test it
#ContextConfiguration(classes={TestSystemConfig.class})
#RunWith(SpringRunner.class)
#WebMvcTest(UserResourceController.class)
public class UserResourceControllerTests {
#Autowired
private MockMvc mvc;
#MockBean
private UserResourceController UserResourceController;
#Test
public void getUser() throws Exception {
mvc.perform(get("/api/users/1")
.with(user("pere.peris#gmail.com").password("password"))
.contentType(APPLICATION_JSON))
.andExpect(status().isOk());
}
}
But I got this error when I run the test:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: Name for argument type [long] not available, and parameter name information not found in class file either.
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:982)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:71)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.springframework.mock.web.MockFilterChain$ServletFilterProxy.doFilter(MockFilterChain.java:166)
at org.springframework.mock.web.MockFilterChain.doFilter(MockFilterChain.java:133)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320)
The reason is because you are mocking your controller. This is not necessary when you have #WebMvcTest(UserResourceController.class)
This should work.
#ContextConfiguration(classes={TestSystemConfig.class})
#RunWith(SpringRunner.class)
#WebMvcTest(UserResourceController.class)
public class UserResourceControllerTests {
#Autowired
private MockMvc mvc;
#Test
public void getUser() throws Exception {
mvc.perform(get("/api/users/1")
.with(user("pere.peris#gmail.com").password("password"))
.contentType(APPLICATION_JSON))
.andExpect(status().isOk());
}
}

Inject EntityManager in SwitchYard Junit implementation

I am trying to implement Junit in SwitchYard Application.
i am using JPA , without using Camel. i have persistence.xml with the following details. And i am using resource producer pattern to expose EntityManager.
But when i am testing a service, i am getting null Invocation for EntityManager in DAO layer.
Is there any way , i can mock or inject EntityManager in SwitchYard Junit
#RunWith(SwitchYardRunner.class)
#SwitchYardTestCaseConfig(config = SwitchYardTestCaseConfig.SWITCHYARD_XML, mixins = {
CDIMixIn.class, HTTPMixIn.class, NamingMixIn.class })
public class SalesModuleServiceTest {
private SwitchYardTestKit testKit;
private CDIMixIn cdiMixIn;
private HTTPMixIn httpMixIn;
private static NamingMixIn namingMixIn;
private TransformerRegistry transformerRegistry;
#ServiceOperation("SalesModuleService")
private Invoker service;
//------ JUnit test with REST binding fails if no resteasy properties defined ------
#BeforeDeploy
public void setProperties()
{
System.setProperty("org.switchyard.component.resteasy.standalone.port", "8081");
System.setProperty("org.switchyard.component.resteasy.standalone.path", "");
}
#Test
public void testUpdateCustomerStatus() throws Exception {
SalesDetailsRequest message = null;
BudgetResponse<?> result = service.operation("updateCustomerStatus")
.sendInOut(message).getContent(SalesResponse.class);
// validate the results
Assert.assertTrue("Implement me", false);
}
}

JBoss AS7 + RestEasy : How to enable a custom MessageBodyReader using #Provider did nothing

I have a wierd problem. I'm using #Provider to annote my Mapper Exception and it's work fine, but when I'm using it to annote the class below it won't work at all.
#Consumes("application/x-java-serialized-object")
#Provider
public class JAXBSpecificMarshaller implements MessageBodyReader
{
#PersistenceContext(unitName = "primary", type = PersistenceContextType.EXTENDED)
private EntityManager em;
#Override
public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mediaType)
{
return type.isAnnotationPresent(XmlRootElement.class);
}
#Override
public Object readFrom(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap httpHeaders, InputStream entityStream) throws IOException, WebApplicationException
{
try
{
// DataAdapter dataAdapter = new DataAdapter(em);
//unmarshaller.setAdapter(dataAdapter);
System.out.println(type.getName());
JAXBContext ctx = JAXBContext.newInstance(type);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
return unmarshaller.unmarshal(entityStream);
}
catch ( JAXBException ex )
{
throw new RuntimeException(ex);
}
}
}
My main reason is to be able to use specific adapter to retrieve an object by passing its id in the input xml. I followed this Serialize a JAXB object via its ID? . But to initialize the adapter with my enitymanger I was told to use MessageBodyReader to do so.
Thank you for your help.
Can you provide some context on what application server you are deploying to and what JAX-RS implementation you are using?
I had a similar problem with RESTeasy on JBoss AS 7 trying to implement a #Produces #Provider for some JAXB annotated classes, but the provided JAXB marshaller provider from RESTeasy always took precedence, and my marshaller never got executed.
My solution was to write implementations for custom JAXBContextFinder, ContextResolver and JAXBContext. I used resteasy-jettison-provider source code as a recipe for implementing my own handlers. http://docs.jboss.org/resteasy/docs/2.0.0.GA/userguide/html/Built_in_JAXB_providers.html