Jersey JSON to object conversion using MOXY not working - java

I am learning the jersey #POST REST call for a simple method which takes in json and returns a simple text. I am using MOXY with Jersey.
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>2.28</version>
</dependency>
My method looks as follows:
#Path("/travel")
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.TEXT_PLAIN)
public String testServletPost(ThingsToSeeInParis thingsToSeeInParis)
{
if (thingsToSeeInParis != null){
System.out.println("thingsToSeeInParis.isSeenEiffeltower() "+thingsToSeeInParis.isSeenEiffeltower());
System.out.println("thingsToSeeInParis.isSeenLouvre() "+thingsToSeeInParis.isSeenLouvre());
System.out.println("thingsToSeeInParis.isSeenMontMaetre() "+thingsToSeeInParis.isSeenMontMaetre());
System.out.println("thingsToSeeInParis.id "+thingsToSeeInParis.getId());
}
if (thingsToSeeInParis.isSeenEiffeltower() && thingsToSeeInParis.isSeenLouvre()){
System.out.println("Please shut up the lady behind me");
return "OK";
}
else{
System.out.println("Its a lost case!");
return "Not OK";
}
}
My ThingsToSeeInParis class is simple POJO class. Looks as follows:
public class ThingsToSeeInParis {
private boolean seenEiffeltower;
private boolean seenMontMaetre;
private boolean seenLouvre;
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public boolean isSeenEiffeltower() {
return seenEiffeltower;
}
public void setSeenEiffeltower(boolean seenEiffeltower) {
this.seenEiffeltower = seenEiffeltower;
}
public boolean isSeenMontMaetre() {
return seenMontMaetre;
}
public void setSeenMontMaetre(boolean seenMontMaetre) {
this.seenMontMaetre = seenMontMaetre;
}
public boolean isSeenLouvre() {
return seenLouvre;
}
public void setSeenLouvre(boolean seenLouvre) {
this.seenLouvre = seenLouvre;
}
}
When I call this method from POSTMAN I get 200 response code but it always returns "Not OK". My postman calls are as follows:
No matter what or how many inputs I put I always get the same output. MOXY is just initializing all the values to default and that is why evaluation is not working. Can someone spot the issue in this code? Please let me know. Thank you.

Related

How to create a domain object from a Json element?

the external web service returns me a Json file of the form
{"forecasts":[{"period_end":"2021-01-15T01:00:00.0000000Z","period":"PT30M","ghi90":0,"ghi":0,"ghi10":0},{"period_end":"2021-01-15T01:30:00.0000000Z","period":"PT30M","ghi90":0,"ghi":0,"ghi10":0},{"period_end":"2021-01-15T02:00:00.0000000Z","period":"PT30M","ghi90":0,"ghi":0,"ghi10":0}]}
Using RestRespone a transform an json element
RestResponse resp = rest.get(url)
resp.json instanceof JsonElement
How can I create a domain object from the Json element variable, knowing that my wrapper class is
class ForecastGhi {
static constraints = {
}
private ArrayList<IrradianciaGlobalHorizontal> forecast
ArrayList<IrradianciaGlobalHorizontal> getForecast() {
return forecast
}
void setForecast(ArrayList<IrradianciaGlobalHorizontal> forecast) {
this.forecast = forecast
}
}
and de persist domain class is
class IrradianciaGlobalHorizontal {
static constraints = {
}
#JsonProperty("all")
private def period_end
private def period
private def ghi90
private def ghi
private def ghi10
def getGhi() {
this.ghi
}
void setGhi(int ghi) {
this.ghi = ghi
}
def getGhi90() {
this.ghi90
}
void setGhi90(int ghi90) {
this.ghi90 = ghi90
}
def getGhi10() {
this.ghi10
}
void setGhi10(int ghi10) {
this.ghi10 = ghi10
}
def getPeriod_end() {
this.period_end
}
void setPeriod_end(Date period_end) {
this.period_end = period_end
}
def getPeriod() {
this.period
}
void setPeriod(String period) {
this.period = period
}
}
Help please; thanks a lot
This is an issue with your API implementation; The endpoint changed the domain field names &/or domain name. This will cause issues with bringing said data back in.
Either that or front-end is not matching the API docs for the endpoint.
Field names/domain names should match the domain/resource unless you are going for a level of obfuscation and then accept that you are going to need a middle layer to act as a translater (ie EDI).
You want output to be able to be read as input by the same endpoint by merely changing the request method.
My suggestion (easiest solution): change original endpoint to match domain/resource field names
If you have the opportunity to use Jackson library, you can do this:
ForecastGhi request = objectMapper.readValue(jsonAsText, ForecastGhi.class);
Create an objectMapper and configure to fail in case of unknown properties (just in case)
private String getJsonAsTextFromRest() {
String message = " {\"forecasts\":[{\"period_end\":\"2021-01-15T01:00:00.0000000Z\",\"period\":\"PT30M\",\"ghi90\":0,\"ghi\":0,\"ghi10\":0},{\"period_end\":\"2021-01-15T01:30:00.0000000Z\",\"period\":\"PT31M\",\"ghi90\":0,\"ghi\":0,\"ghi10\":0},{\"period_end\":\"2021-01-15T02:00:00.0000000Z\",\"period\":\"PT32M\",\"ghi90\":0,\"ghi\":0,\"ghi10\":0}]}";
return message;
}
#Override
public void run(String... arg0) throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, true);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
String jsonAsText = getJsonAsTextFromRest();
ForecastGhi request = objectMapper.readValue(jsonAsText, ForecastGhi.class);
request.getForecast().stream().forEach(it -> System.out.println(it.getPeriod() + " " + it.getGhi()));
}
public class IrradianciaGlobalHorizontal {
private Date period_end;
private String period;
private int ghi90;
private int ghi;
private int ghi10;
public int getGhi() {
return this.ghi;
}
public void setGhi(int ghi) {
this.ghi = ghi;
}
public int getGhi90() {
return this.ghi90;
}
public void setGhi90(int ghi90) {
this.ghi90 = ghi90;
}
public int getGhi10() {
return this.ghi10;
}
void setGhi10(int ghi10) {
this.ghi10 = ghi10;
}
public Date getPeriod_end() {
return this.period_end;
}
public void setPeriod_end(Date period_end) {
this.period_end = period_end;
}
public String getPeriod() {
return this.period;
}
public void setPeriod(String period) {
this.period = period;
}
}
ForecastGhi class.
import com.fasterxml.jackson.annotation.JsonProperty;
public class ForecastGhi {
private ArrayList<IrradianciaGlobalHorizontal> forecast;
#JsonProperty("forecasts")//It must be the same as the json property
public ArrayList<IrradianciaGlobalHorizontal> getForecast() {
return forecast;
}
#JsonProperty("forecasts")
public void setForecast(ArrayList<IrradianciaGlobalHorizontal> forecast) {
this.forecast = forecast;
}
}
Results:
PT30M 0
PT31M 0
PT32M 0
Dependencies Gradle:
compile group: 'com.fasterxml.jackson.core', name: 'jackson-core', version: '2.12.1'
Or
Dependencies Maven:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.1</version>
</dependency>
Note: in your json example you use forecasts, but your java property name is forecast. In that case its necessary to decorate the property with #JsonProperty("forecasts"). If you dont do it, you get an error like this com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "forecasts"

How to get the body from a POST call. JAX-RS

I make a POST-type call in eclipse / java using JAX-RS
I can not handle the return in the method predictCid
This method sends the textToPredict parameter and receives a return string, how can I get this value and set it to the variable, textPredicted?
#Path("Predicao")
public class PredicaoCIDResource extends BaseResource {
#POST
#Path("predicaoCid")
public RetornoGenerico<PredicaoCidVo> predizerCid(PredicaoCidVo predicaoVo) {
System.out.print("\nentrou no método java");
RetornoGenerico<PredicaoCidVo> retorno = new RetornoGenerico<PredicaoCidVo>();
String nomeMetodo = "predicaoCid";
super.criarRetornoSucesso(nomeMetodo, retorno);
System.out.print("passou pelo super");
try {
System.out.print("\nentrou no try");
PredicaoCidVo predicaoCidVo = new PredicaoCidVo();
Response retornoPred = predictCid(predicaoVo.getTextToPredict());
System.out.print("retornou do método predict");
predicaoCidVo.setTextPredicted(retornoPred.getEntity().toString());
retorno.setRetorno(predicaoCidVo);
} catch (Exception e) {
super.trataExececao(retorno, e, nomeMetodo);
}
return retorno;
}
#POST
#Path("http://127.0.0.1:5000/predict")
#Consumes("application/x-www-form-urlencoded")
private Response predictCid(#FormParam("textToPredict") String predicaoVo) throws IOException {
System.out.print("\nentrou no método predict");
//How get te return ??? String
}
PredicaoVo:
#XmlRootElement
public class PredicaoCidVo implements Serializable {
/**
*
*/
private static final long serialVersionUID = 2471424108047814793L;
private String textToPredict;
private String textPredicted;
public String getTextToPredict() {
return textToPredict;
}
public void setTextToPredict(String textToPredict) {
this.textToPredict = textToPredict;
}
public String getTextPredicted() {
return textPredicted;
}
public void setTextPredicted(String textPredicted) {
this.textPredicted = textPredicted;
}
}
The call is made correctly (predictCid), returns with status 200 (OK).
But, I can not return in one of the class variables PredicaoVo.
How do I make this return by filling in, for example, the textPredicted object?
The return, within the method that does the POST, is a simple string
Below, the feedback I have on SOAPUI testing:
<Response xmlns="http://app-homolog/overcare-ws/rest/Profissional/predicaoCid">
<retorno>
<textPredicted>predicao.PredicaoCidVo#3372c9d7</textPredicted>
<textToPredict null="true"/>
</retorno>
<retornoMensagem>
<dsMensagem>predicaoCid.sucesso</dsMensagem>
<dsStackTrace null="true"/>
<dsTitulo>predicaoCid.titulo</dsTitulo>
<idCamada>SUCESSO</idCamada>
</retornoMensagem>
</Response>
Who sends the return to the soapUI is the method predizerCid

Request to the server does not pass

I have some backend which adds new data in the database. Link for add new data looks like this:
...handler.php?type=add&comment=ads&idImage=2&idAuthor=3
And response:
{
"success": true
}
And my inteface:
public interface CommentAddRequest
{
#GET("handler.php")
Observable<SimpleResponse> getResponse(#Query("type") String type,
#Query("comment") String comment,
#Query("idImage") Long idImage,
#Query("idAuthor") Long idAuthor
);
}
public class SimpleResponse
{
public Boolean getSuccess()
{
return success;
}
public void setSuccess(Boolean success)
{
this.success = success;
}
#SerializedName("success")
#Expose
private Boolean success;
}
I formirate requset like this:
public static Observable<SimpleResponse> addComment(String comment, Long idImage, Long idAuthor)
{
String type = "add";
CommentAddRequest service = ServiceGenerator.createService(CommentAddRequest.class);
return service.getResponse(type, comment, idImage, idAuthor);
}
}
I debug my code and everything is normal. Request is sends. But in DB doesn't add new data. Though through the browser it works normal. I don't have idea where i should looking up the error. Can you help me?

Java, Storing JSON Array to class and calling it from other class

I am trying to pull data from class in another class and populate a JPanel with the data, but it is not working for some reason.
Here is the full restConnector class where I pull the JSON data.
As far as I know this works fine.
public class restConnector {
private static final Logger LOGGER = LoggerFactory.getLogger(restConnector.class);
private static final restConnector INSTANCE = new restConnector();
public static restConnector getInstance() {
return restConnector.INSTANCE;
}
private restConnector(){
}
private static String user = "ss";
private static String pwd = "ee
public static String encode(String user, String pwd) {
final String credentials = user+":"+pwd;
BASE64Encoder encoder = new sun.misc.BASE64Encoder();
return encoder.encode(credentials.getBytes());
}
//Open REST connection
public static void init() {
restConnector.LOGGER.info("Starting REST connection...");
try {
Client client = Client.create();
client.addFilter(new LoggingFilter(System.out));
WebResource webResource = client.resource("https://somewebpage.com/
String url = "activepersonal";
ClientResponse response = webResource
.path("api/alerts/")
.queryParam("filter", ""+url)
.header("Authorization", "Basic "+encode(user, pwd))
.header("x-api-version", "1")
.accept("Application/json")
.get(ClientResponse.class);
if (response.getStatus() != 200) {
}else{
restConnector.LOGGER.info("REST connection STARTED.");
}
String output = response.getEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setPropertyNamingStrategy(new MyNameStrategy());
try {
List<Alert> alert = mapper.readValue(output, new TypeReference<List<Alert>>(){});
} catch (JsonGenerationException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void close() {
}
}
However, when I try to pull the data in another class it gives me just null values from the system.out.print inside refreshData() method. Here is the code that is supposed to print the data
public class Application{
Alert alerts = new Alert();
public Application() {
refreshData();
}
private void initComponents() {
restConnector.init();
refreshData();
}
private void refreshData() {
System.out.println("appalertList: "+alerts.getComponentAt(0));
}
}
Here is my Alert class
#JsonIgnoreProperties(ignoreUnknown = true)
#JsonInclude(Include.NON_EMPTY)
public class Alert {
private int pasID;
private String status;
private boolean shared;
private String header;
private String desc;
public int getPasID() {
return pasID;
}
public void setPasID(int pasID) {
this.pasID = pasID;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public boolean isShared() {
return shared;
}
public void setShared(boolean shared) {
this.shared = shared;
}
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("\n***** Alert Details *****\n");
sb.append("PasID="+getPasID()+"\n");
sb.append("Status="+getStatus()+"\n");
sb.append("Shared="+isShared()+"\n");
sb.append("Header="+getHeader()+"\n");
sb.append("Description="+getDesc()+"\n");
sb.append("*****************************");
return sb.toString();
}
public String getComponentAt(int i) {
return toString();
}
}
I'm kind a lost with this and been stuck here for a couple of days already so all help would be really appreciated. Thanks for the help in advance.
Edit: Formatted the code a bit and removed the NullPointerException as it was not happening anymore.
As stated in comments:
Me: In your first bit of code you have this try { List<Alert> alert.., but you do absolutely nothing with the newly declared alert List<Alert>. It this where the data is supposed to be coming from?
OP: I'm under the impression that that bit of code is the one that pushes the JSON Array to the Alert.class. Is there something I'm missing there?
Me: And what makes you think it does that? All it does is read the json, and the Alert.class argument is the class type argument, so the mapper know the results should be mapped to the Alert attributes when it creates the Alert objects. That's how doing List<Alert> is possible, because passing Alert.class decribes T in List<T>. The List<Alert> is what's returned from the reading, but you have to determine what to actually do with the list. And currently, you do absolutely nothing with it
You maybe want to change the class just a bit.
Now this is in no way a good design, just an example of how you can get it to work. I would take some time to sit and think about how you want the restConnector to be fully utilized
That being said, you can have a List<Alert> alerts; class member in the restConnector class. And have a getter for it
public class restConnector {
private List<Alert> alerts;
public List<Alert> getAlerts() {
return alerts;
}
...
}
Then when deserializing with the mapper, assign the value to private List<Alert> alerts. What you are doing is declaring a new locally scoped list. So instead of
try {
List<Alert> alert = mapper.readValue...
do this instead
try {
alerts = mapper.readValue
Now the class member is assigned a value. So in the Application class you can do something like
public class Application {
List<Alert> alerts;
restConnector connect;
public Application() {
initComponents();
}
private void initComponents() {
connector = restConnector.getInstance();
connector.init();
alerts = connector.getAlerts();
refreshData();
}
private void refreshData() {
StringBuilder sb = new StringBuilder();
for (Alert alert : alerts) {
sb.append(alert.toString()).append("\n");
}
System.out.println("appalertList: "+ sb.toString());
}
}
Now you have access to the Alerts in the list.
But let me reiterate: THIS IS A HORRIBLE DESIGN. For one you are limiting the init method to one single call, in which it is only able to obtain one and only one resource. What if the rest service needs to access a different resource? You have made the request set in stone, so you cant.
Take some time to think of some good OOP designs where the class can be used for different scenarios.

Rest Easy Client Framework value lost after unmarshaling

Yesterday I tried to use the client side of the RestEasy framework. The interface has a method:
#PUT
#Path("document/autoincrement")
#Consumes("application/xml")
BaseClientResponse<String> insertPointOfInterest(PoiDocument poiDocument);
and the call to some (Jersey) rest service looks like:
String restServerServiceUrl = "http://my.jersey.server/rest/serviceFoo/v1/";
NSSClientService client = ProxyFactory.create(NSSClientService.class, restServerServiceUrl);
PoiDocument poiDocument = new PoiDocument("Parkirišče", "90", 390262.85133115170, 42240.33558245482);
BaseClientResponse<String> response = client.insertPointOfInterest(poiDocument);
assert response.getResponseStatus() == Response.Status.OK;
// Expected result
//<?xml version="1.0" encoding="UTF-8" standalone="yes"?><insertedRecord><record>14</record></insertedRecord>
logger.info("Returned: " + response.getEntity());
And the logger prints:
14
Kind of expected.
But I want an object not a string, so I can easely assert the values returned. The interface:
#PUT
#Path("document/autoincrement")
#Consumes("application/xml")
BaseClientResponse<InsertedResponse> insertPointOfInterest(PoiDocument poiDocument);
Instead of String there is now a InsertedResponse class which looks like:
#XmlRootElement(name="insertedRecord")
public class InsertedResponse extends ResponseResult{
String insertedRecord;
public InsertedResponse(int insertedRecord) {
this.insertedRecord = Integer.toString(insertedRecord);
}
public InsertedResponse(){
insertedRecord = "";
}
#XmlElement(name="record")
public String getInsertedRecords(){
return insertedRecord;
}
public void add(int recNo) {
insertedRecord = Integer.toString(recNo);
}
}
...and its superclass:
#XmlRootElement(name = "result")
public abstract class ResponseResult {
protected String getClearString(String string) {
if (string != null) {
return Constants.removeInvalidXMLCharacters(string);
}
return "";
}
}
Now, when I change the client call also to:
BaseClientResponse<InsertedResponse> response = client.insertPointOfInterest(poiDocument);
logger.info("Returned: " + response.getEntity().getInsertedRecords());
I get an empty string instead of some value.
So, the question is - where did the value of go? It should print a number, like 14 in the above example.
One missing JAXB annotation (#XmlSeeAlso)
#XmlRootElement(name = "result")
#XmlSeeAlso( { InsertedResponse.class, OtherChild.class, SomeOtherChild.class })
public abstract class ResponseResult {
...
}
and an added setter method
#XmlRootElement(name="insertedRecord")
public class InsertedResponse extends ResponseResult{
...
public void setInsertedRecords(String insertedRecord) {
this.insertedRecord = insertedRecord;
}
solved the problem.

Categories

Resources