Jersey 2 InjectLink is ignored - json

I'm creating a new Jersey 2.21, Jackson 2.6.1 REST server (I tried with Jersey 2.19 and Jackson 2.5.3 as well) and a want to use #InjectLink to provide HATEOAS links (like 'self') for my callers. The most basic app (taken from Jersey doc and Jersey sample apps) isn't working, and I can't figure out why.
I started by taking the basic Widgets class from the Jersey doc, but the JSON or XML returned is just an empty structure.
XML:
<Widgets/>
JSON:
{}
Widgets.java
package org.glassfish.jersey.examples.linking;
import java.net.URI;
import java.util.List;
import javax.ws.rs.core.Link;
import javax.xml.bind.annotation.XmlRootElement;
import org.glassfish.jersey.linking.InjectLink;
import org.glassfish.jersey.linking.InjectLinks;
#XmlRootElement()
public class Widgets {
#InjectLink(resource=WidgetsResource.class)
URI u;
#InjectLinks({#InjectLink(resource=WidgetsResource.class, rel = "self")})
List<Link> links;
public Widgets() {}
}
I put a breakpoint in the resource code and examined the object being returned. it.links and it.u are both null. There's nothing injected.
WidgetsResource.java
#Path("widgets")
public class WidgetsResource {
#GET
public Widgets get() {
Widgets it = new Widgets();
return it;
}
}
Maven dependencies:
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-declarative-linking</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.el</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
<version>2.2.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-joda</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-xml-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-yaml-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
</dependencies>
<properties>
<jersey.version>2.21</jersey.version>
<jackson.version>2.6.1</jackson.version>
</properties>
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>Server</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>org.glassfish.jersey.examples.linking.Server</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/rest/v1/*</url-pattern>
</servlet-mapping>
</web-app>
The application object:
package org.glassfish.jersey.examples.linking;
import org.glassfish.jersey.linking.DeclarativeLinkingFeature;
import org.glassfish.jersey.server.ResourceConfig;
public class Server extends ResourceConfig {
public Server() {
packages("org.glassfish.jersey.examples.linking",
"com.fasterxml.jackson.jaxrs")
.register(DeclarativeLinkingFeature.class);
}
}
It appears that the #InjectLink(s) annotations are simply being ignored. There must be some magic setting I'm missing, but I've done everything the Jersey doc says to do.
I tried with both Servlet 2.x (shown) and Servlet 3.x (using #ApplicationPath) and that made no difference.
Some of you will notice from my package names that I also tried the slightly more advanced, but no more successful, Jersey declarative linking example (https://github.com/jersey/jersey/tree/master/examples/declarative-linking). Some of the basic fields were returned, but all of the injected links were missing or null.
.../Server/rest/v1/items/1 produced:
{
"id": "1",
"nextId": "2",
"prevId": "0",
"prev": true,
"next": true
}
FYI - I'm running Java 1.8.0_60, Eclipse Mars, and Tomcat 8.0.26. There are no errors, no warnings and no runtime messages. I'm completely stumped. Anyone have any pointers???

I have added the following to my servlet config:
`<init-param>
<param-name>jersey.config.server.provider.classnames</param-name>
<param-value>
org.glassfish.jersey.linking.DeclarativeLinkingFeature
</param-value>
</init-param>'
and the links were rendered in the json response.

For information, if you do not want to use web.xml config file, you can do that:
import javax.ws.rs.ApplicationPath;
import org.glassfish.jersey.linking.DeclarativeLinkingFeature;
import org.glassfish.jersey.server.ResourceConfig;
#ApplicationPath("rest/v1")
public class MyApp extends ResourceConfig {
public MyApp () {
packages("the.package.where.your.services.are.located")
.register(DeclarativeLinkingFeature.class);
}
}

Related

Cucumber With JUnit Undefined Step Exception

I'm new to the UnitTesting and Cucumber, and today I tried to implement a simple example from a tutorial in Eclipse and I got error when I try run the RunnerClass.java.
My Pom file
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>belajar1</groupId>
<artifactId>belajar1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>9</release>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>3.0.0-beta4</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-java</artifactId>
<version>6.10.2</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-junit</artifactId>
<version>6.10.2</version>
</dependency>
</dependencies>
</project>
My feature file
Feature: Gmail Testing
Scenario: Gmail Login
Given url opened
Then enter user id and click next
Then enter password
And click login
Scenario: Gmail Close
Then Close browser
My Definition file
public class stepDefinition {
public static WebDriver obj=null;
#Given("^url opened$")
public void url_opened() throws Throwable{
System.setProperty("webdriver.gecko.driver","D:\\Installed APP\\Eclipse Workspace\\Webdriver\\geckodriver.exe");
obj=new FirefoxDriver();
obj.manage().window().maximize();
obj.get("https://mail.google.com");
}
#Then("enter user id and click next")
public void enter_user_id_and_click_next() throws InterruptedException{
obj.findElement(By.id("Email")).sendKeys("YOURUSERID");
obj.findElement(By.id("next")).click();
Thread.sleep(2000);
}
#Then("^enter password$")
public void enter_password(){
obj.findElement(By.id("Passwd")).sendKeys("YOURPASSWORD");
}
#Then("^click login$")
public void click_login() throws InterruptedException{
obj.findElement(By.id("signIn")).click();
Thread.sleep(6000);
}
#Then("^close browser$")
public void close_browser(){
obj.quit();
}
}
My Runner file
package tester;
import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
#RunWith(Cucumber.class)
#CucumberOptions(
features="src/test/resources/demo.feature",
glue="definition.stepDefinition",
plugin = {
"pretty",
"html:target/report", //create a folder called cucumber
"json:target/report.json",
//Notice the corresponding file extension (.json) telling cucumber to create a file
// "com.cucumber.listener.ExtentCucumberFormatter:target/report.html"
//Notice I remove the white space at :target/report.html
}
)
public class RunnerClass {
}
I keep got this error
enter image description here
Also this my Library
enter image description here

Spring-boot 2 and swagger 2 (springfox) does not show model

I have created my patch endpoint (Json path specified in RFC 6902).
At UI generated by springfox my endpoint is shown, but the model example (only patch) did not show.
To use Json patch in my Spring-boot 2 project I have used that dependency on pom.xml.
<dependencies>
<dependency>
<groupId>com.github.java-json-tools</groupId>
<artifactId>json-patch</artifactId>
<version>1.12</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.11.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<scope>compile</scope>
</dependency>
</dependencies>
At my endpoint, my code is:
#RestController
#RequestMapping(value = "/operation", produces = "application/json")
public class IntentController {
#RequestMapping(value = "/{id}",
method = RequestMethod.PATCH,
consumes = "application/json-patch+json")
public void updateValue(#PathVariable Long id, #RequestBody JsonPatch patch){ {
// ... do magic
}
#RequestMapping(value = "/{id}",
method = RequestMethod.GET)
public MyDto getValue(#PathVariable Long id){ {
MyDto dto = service.findById(id);
return dto;
}
#RequestMapping(method = RequestMethod.POST)
public void updateValue(#RequestBody MyDto dto){ {
service.insert(dto);
}
}
My GET and POST endpoints are generated fine with their example models in UI.
Only PATCH doesn't work fine... their example model didn't generate.
The problem lies with JsonPatch object, this object does not have any getter method, so Springfox library could not generate the model for request.
One possible solution may be like , you create a custom MyJsonPatch POJO with getter and setter and create a JsonPatch with the data of MyJsonPatch.
I can't found a solution to my problem, so I decided to use #ApiParam from Swagger to describe that this field is an RFC 6902 implementation.

No MonetaryAmountsSingletonSpi loaded

Dependency added in pom.xml:
<dependency>
<groupId>javax.money</groupId>
<artifactId>money-api</artifactId>
<version>1.0.3</version>
</dependency>
Relevant code:
MonetaryAmount mon = Monetary.getDefaultAmountFactory()
//getCurrency() returns String
.setCurrency(amount.getCurrency())
//getContent() returns BigDecimal
.setNumber(amount.getContent())
.create();
when unittesting i get this exception:
javax.money.MonetaryException: No MonetaryAmountsSingletonSpi loaded.
at javax.money.Monetary.lambda$getDefaultAmountFactory$13(Monetary.java:291)
JavaMoney is split into separate packages for API and implementation, but you added only the API to your POM. You also need an implementation, e.g. the reference implementation:
<dependency>
<groupId>org.javamoney</groupId>
<artifactId>moneta</artifactId>
<version>1.2.1</version>
<type>pom</type>
</dependency>

Jersey 2.x using Pojo as Parameter for POST

I'm having some trouble with NPE's while trying to use POJOS as Parameters.
I'm deploying the war maven generates to a tomcat 7 with default configurations.
The signature of my method looks like this.
#POST
#Produces({MediaType.APPLICATION_JSON})
#Consumes({MediaType.APPLICATION_JSON})
#Path("/do/")
public OtherPojo doSomething(MyPOJO pojo) {
The Pojo is annotated with #XmlRootElement
However when I invoke the url, the pojo is null and thus I get th NPE.
My pom.xml
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-metainf-services</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet</artifactId>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>${jackson.version}</version>
</dependency>
I've tried with jersey 2.13 and 2.6
And jackson 2.4
Additionally I didnt set up an Application, my classes just have the annotation
#Path("/somePath/")
public class SomeClass {
And this is configured in my web.xml
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.beer.routes</param-value>
</init-param>
I read I might need to Register the JacksonFeature, but I couldn't figure out how to do that.
After further review, the code above works fine.
The problem was when calling the class, I was sending the payload with lowercased names.
The POJO looks like
private String someString;
public void getSomeString() { ... }
public String setSomeString (String s) {...}
The problem in my payload was me sending "someString" instead of "SomeString".
This is very relevant as it was the cause that my object was received as null.
After changing the payload the error changed to this.
Jackson with JSON: Unrecognized field, not marked as ignorable

Spring 3.1.1 and json getting error 406

I have written a simple rest based controller using #responseBody which I expect to return a JSON.
Somehow I am not able to get it work as expected.
when I run the url "http://localhost:8080/my-webapp/amazon/rips" ..it throws back below error
HTTP Status 406 -JBWEB000126: The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request 'Accept' headers.
can someone please lend a helping hand.
Mycontroller is below:
#Controller
#RequestMapping("/amazon")
public class JsonController {
#RequestMapping(value="/{name}", method = RequestMethod.GET,produces = "application/json")
public #ResponseBody
Book getShopInJSON(#PathVariable String name) {
Book book = new Book();
book.setName(name);
book.setAvailablity(false);
return book;
}
Book class is below:
public class Book {
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isAvailablity() {
return availablity;
}
public void setAvailablity(boolean availablity) {
this.availablity = availablity;
}
private String name ;
private boolean availablity;
}
displatcher servlet is as below:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd">
<context:component-scan base-package="com.rips.controller" />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/pages/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.1.1.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-core-asl</artifactId>
<version>${jackson.version}</version>
</dependency>
with the help from #CodeChimp I realized that request that I was sending was not having proper accept headers.
I used Chromes "Advanced Rest client" and added headers with key ="accept" and value ="application/json",I was able to get proper response.
update
I found that <mvc:annotation-driven /> was not added in the dispatcher servlet which configures the support for HTTP message conversion with #RequestBody/#ResponseBody.Once I added this piece of info there was no need to use any advanced Rest client.