NetBeans webservice client stubs - incompatible type? - java

I generated my client side stubs for a NetBeans webservice.
The webservice implementation uses a local POJO from my project. The generated stubs have created a revision of this POJO for use. When I'm using the service, I want to use the original POJO, not the generated type..? Type casting doesn't work.
i.e. (note the packages)
package adiib.ws.harmoniser;
#WebMethod(operationName = "getStartupLogMessages")
public ArrayList<LogMessage> getStartupLogMessages() {
return startupLogMessages;
}
The POJO LogMessage reads:
package adiib.shared;
public class LogMessage implements Serializable
{
private static final long serialVersionUID = 8379681391654158512L;
private String exceptionMessage;
private String customMessage;
private String stackTrace;
private LogMessageEnum classification;
private String effectiveTime;
private String exceptionClassName;
private String throwerClassName;
public LogMessage(){}
public LogMessage(String exceptionMessage, String customMessage,
String stackTrace, LogMessageEnum classification, String effectiveTime,
String exceptionClassName, String throwerClassName)
{
this.exceptionMessage = exceptionMessage;
this.customMessage = customMessage;
this.stackTrace = stackTrace;
this.classification = classification;
this.effectiveTime = effectiveTime;
this.exceptionClassName = exceptionClassName;
this.throwerClassName = throwerClassName;
}
public String getCustomMessage() {
return customMessage;
}
public void setCustomMessage(String customMessage) {
this.customMessage = customMessage;
}
public String getExceptionMessage() {
return exceptionMessage;
}
public void setExceptionMessage(String exceptionMessage) {
this.exceptionMessage = exceptionMessage;
}
public LogMessageEnum getClassification() {
return classification;
}
public void setClassification(LogMessageEnum classification) {
this.classification = classification;
}
public String getEffectiveTime() {
return effectiveTime;
}
public void setEffectiveTime(String effectiveTime) {
this.effectiveTime = effectiveTime;
}
public String getStackTrace() {
return stackTrace;
}
public void setStackTrace(String stackTrace) {
this.stackTrace = stackTrace;
}
public String getExceptionClassName() {
return exceptionClassName;
}
public void setExceptionClassName(String exceptionClassName) {
this.exceptionClassName = exceptionClassName;
}
public String getThrowerClassName() {
return throwerClassName;
}
public void setThrowerClassName(String throwerClassName) {
this.throwerClassName = throwerClassName;
}
}
Now, on the client side when I'm trying to use the webservice method like so:
package adiib.server;
private void getStartupLogMessages() {
private static List<LogMessage> logMessages = new ArrayList<LogMessage>();
dsto.adiib.ws.client.harmoniser.AdiibHarmoniser_Service service = new dsto.adiib.ws.client.harmoniser.AdiibHarmoniser_Service();
dsto.adiib.ws.client.harmoniser.AdiibHarmoniser port = service.getAdiibHarmoniserPort();
List<dsto.adiib.ws.client.harmoniser.LogMessage> startupLogMessages = port.getStartupLogMessages();
for (adiib.ws.client.harmoniser.LogMessage logMessage : startupLogMessages) {
/*
* this fails becuase it's looking for adiib.ws.client.harmoniser.LogMessage
* not adiib.shared.LogMessage; adiib.ws.client.harmoniser.LogMessage is the
* generated type..
*/
logMessages.add((LogMessage) logMessage);
}
}
Any ideas? All I can think is creating a conversion method.. that seems wrong.
WulfgarPro

The classes generated by the tool are not the same as the original ones you have. So you have to use the tool generated ones in your client side to communicate with the web service. You cannot replace it with the ones you wrote for your server side.
For example, consider JAX-WS built client side DTOs. If you open up the source code, you will see that the auto-generated ones (using wsimport) contains annotations which may not be present (unless you manually wrote) in your server side classes. Therefore, as of my understanding, you have to go with the tool generated ones.
You might have to write methods to transform your DTOs to the tool generated one before web service is invoked. If your generated classes have the same set of properties (type and naming has not been altered by the tool when generating client DTOs), then probably you could use something like Apache Commons BeanUtils (see http://commons.apache.org/beanutils/) to aid in transformation. You can simply call BeanUtils.copyProperties() and pass in your source DTO (your own type) and the target DTO (WS generated) and get it transformed.

you right, generated class for the stub are images of the POJO classes.
They are generated to transfer data from remote server.
You have to use setter/getter and adapt data on your POJO.
Your method need to be wrapped in another method which belong to a service class. (call it MyClassServiceImpl)
and call the method in your application implementation.

Add the following to your LogMessage class (in the service):
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "LogMessage")
public class LogMessage implements Serializable
{ ... }
Rebuild the server.
In your client application, go to Web Service References and Right Click -> Refresh... the service.
The LogMessage class that you want to use will then appear in the Generated Sources folder of the client.

Related

Spring: Nested object does not get deserialized

I'm sending a POST-Request from angular to spring. Its getting deserialized mostly correct, but one nested object is getting deserialized as an empty Object.
My Angular interfaces look as follows:
// ClientMedicalModal.ts
export interface ClientMedicalModal {
clientMedicalId: number;
client: ClientModel;
medicalEvidence: MedicalEvidence;
}
// ClientModal.ts
export interface ClientModal {
clientId: number;
}
// MedicalEvidenceModal.ts
export interface MedicalEvidenceModal {
B001: string;
B003: string;
B004: string;
}
My Java-Objects look like this:
public class ClientMedical implements Serializable {
private Integer clientMedicalId;
private Client client;
private MedicalEvidence medicalEvidence;
// getter and setter
}
public class Client implements Serializable {
private Integer clientId;
// getter and setter
}
public class MedicalEvidence implements Serializable {
private String B001;
private String B003;
private String B004;
public String getB001() {
return B001;
}
public MedicalEvidence setB001(String b001) {
B001 = b001;
}
// all other getter and setter
}
When I check the post message from my browser everything seems to be okay:
{"medicalEvidence":{"B001":"Test","B003":"TestMessage","B004":"Whatever"},"client":{"clientId":1}}
Debugging in Spring I get the request, there is a Client-Object with clientId = 1, but the ClientEvidence-Object is empty, all B00* fields are null.
See here the debugging values
Spring form binding binds the form parameters to respective fields for Client class, but MedicalEvidence is blank, so Spring instantiates a new MedicalEvidence class with all fields having null values. Why does the parameters does not get bound to the MedicalEvidence's class fields but to Client's class (and all other classes I'm using the same way)? Btw. It does not work either if I just send MedicalEvidence from Angular. The object params are still all empty.
Try using b001, b002,.. as names, the first letter should not be uppercase in your use case, except you want to use some annotation. And use 'this.' in the setter method.
public class MedicalEvidence implements Serializable {
private String b001;
private String b003;
private String b004;
^^^^
public String getB001() {
return b001;
}
public MedicalEvidence setB001(String b001) {
this.b001 = b001;
^^^^^
}

No primary or default constructor found for interface java.util.List Rest API Spring boot

I am passing a request body to a POST request on postman similar to this:
"name":"Mars",
"artifacts":[
{
"elements":[
{
"name":"carbon",
"amount":0.5,
"measurement":"g"
}
],
"typeName":"typeA"
},
{
"elements":[
{
"name":"hydrogen",
"amount":0.2,
"measurement":"g"
}
],
"typeName":"typeB"
}
]
The create method in the rest controller looks like this.
#RequestMapping("/create")
public Planet create(#RequestBody Planet data) {
Planet mars = planetService.create(data.getName(),data.getArtifacts());
return mars;
Planet and all its nested objects have a default constructor such as:
public Planet() {}
However, I am not able to create a new planet object because of lack of a default constructor. Please help!
EDIT:
Planet class
public class Planet {
#JsonProperty("name")
private String name;
#Field("artifacts")
private List<Artifact> artifacts;
public Planet() {}
public Planet(String name, List<Artifact> artifacts)
{
this.name = name;
this.artifacts = artifacts;
}
//setters and getters
}
Artifact class:
public class Artifact() {
#Field("elements")
private List<Element> elements;
#JsonProperty("typeName")
private String typeName;
public Artifact() {}
public Artifact(String typeName, List<Element> elements)
{
this.typeName = typeName;
this.elements = elements;
}
}
Element class:
public class Element() {
#JsonProperty("elementName")
private String name;
#JsonProperty("amount")
private double amount;
#JsonProperty("measurement")
private String measurement;
public Element() {}
public Element(String name, double amount, String measurement)
{
//assignments
}
}
I had that the same error when I forgot the #RequestBody before the parameter
#RequestMapping("/create")
public Planet create(#RequestBody Planet data) {
I don't understand what is the issue you are facing, but i can see an error straight away so guessing that is the issue you are facing, i am going to give you a solution.
Create a class which matches your json data structure like this :
Class PlanetData {
private String name;
private List<Planet> artifacts;
public PlanetData(String name, List<Planet> artifacts){
name = name;
artifacts = artifacts;
}
// include rest of getters and setters here.
}
Then your controller should look like this. Basically you needed to put #RequestBody to all the parameters you want to recieve from request JSON. Earlier you only put #RequestBody to name parameter not artifact parameter and since Request Body can be consumed only once, so you need a wrapper class to recieve the complete request body using single #RequestBody annotation.
#RequestMapping("/create")
public String create(#RequestBody PlanetData data) {
Planet mars = planetService.create(data.getName(),data.getArtifacts());
return mars.toString();
}
Edit : Looking at the Planet class, it also needs some modification
public class Planet {
private String typeName; // key in json should match variable name for proper deserialization or you need to use some jackson annotation to map your json key to your variable name.
private List<Element> elements;
public Planet() {}
public Planet(String typeName, List<Element> elements)
{
this.typeName = typeName;
this.elements = elements;
}
//setters and getters. Remember to change your setters and getter from name to typeName.
}
Hope this solves your issue.
This answer too might help someone.
When you are using spring framework for your API development, you may accidently import a wrong library for RequestBody and RequestHeader annotations.
In my case, I accidently imported library,
io.swagger.v3.oas.annotations.parameters.RequestBody
This could arise the above issue.
Please ensure that, you are using the correct library which is
org.springframework.web.bind.annotation.RequestBody
I guess, it’s trying to call new List() which has no constructor. Try using ArrayList in your signatures.
If it works this way, you have found the error. Then rethink your concept of calling methods, since you would usually want to avoid using implementations of List in method signatures
Make sure your request type is not of type GET
If so it is better not to send data as request body.
you should write as below:
...
public String create(#RequestBody JSONObject requestParams) {
String name=requestParams.getString("name");
List<Planet> planetArtifacts=requestParams.getJSONArray("artifacts").toJavaList(Planet.Class);
...

Spring boot restful web service. Xml response wrongly formatted

I've got a simple Restful webService using Spring Boot 2.1, Java 8, running on Eclipse Neon. Im sending the following request:
<patentListWrapper>
<patentList>
<patent>
<guid>bbb</guid>
</patent>
<patent>
<guid>ccc</guid>
</patent>
</patentList>
</patentListWrapper>
and im getting back the following (incorrect) response:
<patentListWrapper>
<patentList>
<patentList>
<guid>ddd</guid>
</patentList>
<patentList>
<guid>eee</guid>
</patentList>
</patentList>
</patentListWrapper>
ie i've got 2 patentList elements in the response ,instead of an inner patent element, and I don't know why. My 2 POJO classes to map the request are:
public class PatentListWrapper {
private List<Patent> patents;
public List<Patent> getPatentList() {
return patents;
}
public void setPatentList(List<Patent> patents) {
this.patents = patents;
}
}
and:
public class Patent {
private String guid;
public String getGuid() {
return guid;
}
public void setGuid(String guid) {
this.guid = guid;
}
public Patent() {
super();
}
}
my REST Controller class is:
#RestController
public class PndController {
#Autowired
ReadFromDb db;
#RequestMapping(value = "/guidRequest/xmlList", method = RequestMethod.POST, produces = { "application/xml", "text/xml" }, consumes = MediaType.ALL_VALUE )
public PatentListWrapper guidSearchList(#RequestBody PatentListWrapper patentListWrapper) {
System.out.println("DS in guidSearchList()");
patentListWrapper = db.readGuidsFromDb(patentListWrapper); // Set the guid in the patents List in patentListWrapper
return patentListWrapper;
}
}
and ReadFromDb class:
#Repository
public class ReadFromDb {
public PatentListWrapper readGuidsFromDb(PatentListWrapper patentListWrapper) {
List<Patent> patents= patentListWrapper.getPatentList();
for(Patent patent : patents) {
patent.setGuid("aaa");
}
patentListWrapper.setPatentList(patents);
return patentListWrapper;
}
}
I'm sending my resuest using the windows ARC Advanced Rest Client:
Rest client with Content-type=application/xml
I've established that both patentList element names map to getPatentList() in PatentListWrapper. How do I get the response envelope to match the request envelop? Any help appreciated.
it is true , just create the getter setter method with the same variable name like below instead of using different names for getter setter methods
private List<Patent> patents;
public List<Patent> getPatents() {
return patents;
}
public void setPatents(List<Patent> patents) {
this.patents = patents;
}
or use the GSON and use #JsonProperty and define the required value name , further if you are not using the IDE to generate getters and setters you better use lombok plugin .

Why aren't static methods on my models available in the Google Cloud Endpoints client libraries?

I have the following Entity as a return value for one of my endpoints. When I generate the client libraries, it seems to ignore the static methods, which leaves Player.key() unavailable. I can't find any documentation anywhere which explains what will be allowed or removed from the client libraries, so I'm trying to figure it out, but some framework for understanding other than trial and error would be helpful.
#Entity
public class Player {
public static final String PLAYER = "Player";
public static final String UUID = "uuid";
public static final String NAME = "name";
#Id
String uuid;
String name;
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public static Key key(String uuid) {
return KeyFactory.createKey(PLAYER, uuid);
}
}
If I rewrite the methods as follows it works:
public Key key(String uuid) {
return KeyFactory.createKey(PLAYER, uuid);
}
But that requires me to do silly things like the following in my client code, which I'd like to avoid:
Key playerKey = new Player().key(uuid);
I apparently can't write this method in a separate class on the client side because I don't have access to the appengine SDK.
The generated client libraries primarily serve to model your data, not to support auxiliary methods. You can include these utilities in another library if you need them. I'm not convinced the non-static version of the method is doing what you want on the client side, if the syntax works, because they client libraries don't copy entities or their dependencies.

how to easily convert a JSON to a string for logging purposes

I will try to explain what I'm trying to accomplish as clear as I can.
I'm writing the back end of a web application, that uses REST APIs for extracting data that is used for reports in the client side.
The framework I'm writing on uses Codehaus jackson for parsing the requests from JSON to data objects (data beans).
I have a bunch of APIs of this sort, 10-15.
each of them gets a different request object from the client side (though some inheritance do exist).
what I want to do is add logging (using log4j) for each of these APIs so that when I enter each of the methods the request data object will be logged.
the simple solution would be to implement a toString() method for each of these data objects, but I want to avoid going over all of these data objects and see if there's a solution similiar to the way that jackson parses the JSON into an object.
I.e have the object converted back to its textual format in order to put it into the log.
I assume there's so easy way to do so.
This is an example of a REST API and its data bean:
#POST
#Path("/path123/")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response getSomeData(#Context HttpServletRequest httpServletRequest, DataBeanExample bean){
DataBeanExample resultBean;
//DO SOME STUFF , for example take the bean, extract parameters from it and call some other api.
return Response.ok(resultBean, MediaType.APPLICATION_JSON).build();
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "DataBeanExample")
public class DataBeanExample{
#XmlElement(name = "timeFrame", required = true)
private String timeFrame = "";
#XmlElement(name = "timeFrom",required = true)
private long timeFrom;
#XmlElement(name = "timeTo",required = true)
private long timeTo;
public String getTimeFrame() {
return timeFrame;
}
public void setTimeFrame(String timeFrame) {
this.timeFrame = timeFrame;
}
public long getTimeTo() {
return timeTo;
}
public void setTimeTo(long timeTo) {
this.timeTo = timeTo;
}
public long getTimeFrom() {
return timeFrom;
}
public void setTimeFrom(long timeFrom) {
this.timeFrom = timeFrom;
}
}
In the example, what I want to do is at the beginning of "getSomeData" take the object bean and have it logged.
Probably this might work
new ObjectMapper().writeValue(System.out, dataBeanExampleInstance)
or writeValueAsString
Do you know about:
JSON.stringify

Categories

Resources