JAXB : How to manipuulate the Data during Unmarshalling process - java

I am using jaxb for the Unmarshalling Process
This is my Request
<kiran acct = "1234567" />
package com;
#XmlRootElement(name = "kiran")
#XmlAccessorType(XmlAccessType.FIELD)
public class CustAcct {
#XmlAttribute
private String acct;
public CustAcct() {
super();
}
public String getAcct() {
System.out.println("The New Getter Method of Account is called");
return acct;
}
public void setAcct(String s) {
System.out.println("The New Setter Method of Account is called");
acct = s;
}
}
This is the way Jersey (Restful Framework ) automatically binds the data with JAXB
public class HelloService {
#POST
#Produces("application/text")
public String sayPlainTextHello(CustAcct custdata) {
System.out.println("The New Account is " + custdata.getAcct());
return "Hi";
}
}
Here my question is that , why the Setter Method setAcct is not getting called in this case ??
I mean why the Line "The New Setter Method of Account is called" isn't being printed , and where as the Line inside the getMethod is geting called (The New Getter Method of Account is called)
Basically I want to Manupulate Data to an Attribute which is sent in the Request XML .
is there any call back method by which i can control the way Data is being Set ??
Thanks in advance .

why the Setter Method setAcct is not getting called in this case ??
Because you set the access type to field: #XmlAccessorType(XmlAccessType.FIELD). Change it to #XmlAccessorType(XmlAccessType.PROPERTY)
XmlAccessType javadoc.
is there any call back method by which i can control the way Data is being Set ??
Yes. You have complete control on the marshall/unmarshall process when you use adapters.

Related

Spring Rest Json Mapping on POST (Invalid Property)

This is a weird one for me. I've done the entities and the controllers and the form validation before, but I'm confused on this error.
So backstory. This is spring-boot w/Hibernate, connecting to a PostgreSQL Db. What I am attempting to do, is map a POST request to creating a resource. I'm trying to do this with pure JSON. I've been able to achieve this before.
The error in question is...
Invalid property 'Test' of bean class [com.example.api.entities.forms.OrganizationRegistrationForm]: Bean property 'Test' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?
The request body, as it is in Postman is...
{
"organizationName":"Test",
"employees":10
}
The OrganizationRegistrationForm class it's complaining about...
public class OrganizationRegistrationForm {
#NotEmpty
private String organizationName = "";
#NotNull
private int employees;
private JsonNode contactInfo;
private JsonNode locationInfo;
public String getOrganizationName() {
return organizationName;
}
public void setOrganizationName(String name) {
this.organizationName = name;
}
public int getEmployees() {
return employees;
}
public void setEmployees(int employees) {
this.employees = employees;
}
public JsonNode getContactInfo() {
return contactInfo;
}
public void setContactInfo(JsonNode contactInfo) {
this.contactInfo = contactInfo;
}
public JsonNode getLocationInfo() {
return locationInfo;
}
public void setLocationInfo(JsonNode locationInfo) {
this.locationInfo = locationInfo;
}
}
And in case you need it, the request method...
#RequestMapping(value="/organization", method = RequestMethod.POST)
public Organization registerOrganization(#Valid #RequestBody OrganizationRegistrationForm form,
BindingResult bindingResult) throws Exception {
if(bindingResult.hasErrors()) {
LOGGER.error("The registration form entered has errors: {}", bindingResult.getAllErrors().toString());
throw new InvalidForm();
}
try {
Organization org = orgService.registerOrganization(form);
if(org!=null)
return org;
} catch(DataIntegrityViolationException e) {
bindingResult.reject("name.exists", "The supplied name is already in use");
}
throw new InvalidForm();
}
Although I'm guessing it doesn't even get that far. Originally the orginazationName field was called "name", but I changed it to see if maybe that was the issue.
The even weirder part for me is when I used this JSON object it worked. But created an organization named "organizationName".
{
"organizationName":"organizationName",
"employees":10
}
And one time it even complained that the invalid property was ''. As in empty. What am I doing wrong here?
I don't know how, or why. But for some reason the answer seemed to be in the OrganizationRegistrationFormValidator class that the binder uses.
The evil line in question was in validate(Object target, Errors errors) method...
ValidationUtils.rejectIfEmptyOrWhitespace(errors, target.getOrganizationName(), "name.empty", "Please enter a name");
Changing that line to a classic check worked.
if(target.getOrganizationName.isEmpty())
errors.reject("name.empty", "Please enter a name");
For documentation sake, anyone know why that happened? Are my api docs wrong when IntelliSense suggested that method signature?
I know this is old but I just stumbled over it:
to me ValidationUtils.rejectIfEmptyOrWhitespace(errors, target.getOrganizationName(), "name.empty", "Please enter a name"); looks wrong.
It should be:
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "organizationName", "name.empty", "Please enter a name");
The second attribute is the Field Name, not its content. ValidationUtils will take that name and transform it to the standard getter (getOrganizationName in that case) to retrieve its value and validate that.
This is why it tells you ther is no property named Test. Because there is none.

Convert an object to a JSON string with thrift json serialization

I'm new to the thrift. I need to convert my data object to a JSON string with Thrift JSON serialization.
I tried in this way.
TSerializer serializer = new TSerializer(new TSimpleJSONProtocol.Factory());
String json = serializer.toString(object_name);
In here is an error, that object_name should be in TBase. How can I resolve this ?
In here is an error, that object_name should be in TBase.
Next time, please post the exact error message (use copy+paste), this makes it easier for all of us.
How can I resolve this?
Whatever you want to serialize with Thrift, must be an descendant of Thrift's TBase class. You achieve this by writing some Thrift IDL and save it as a file (e.g. MyDataStructs.thrift):
struct Employee {
1: string name
2: string surname
3: i32 age
}
Next, you pass that file to the Thrift compiler and tell him to generate some C# code from it:
thrift -gen csharp MyDataStructs.thrift
This gives you a class derived from TBase:
public partial class Employee : TBase
{
private string _name;
private string _surname;
private int _age;
// properties
public string Name {... }
public string Surname { ... }
public int Age { ... }
// some details omitted
public void Read (TProtocol iprot)
{
// generated code for Read() method
}
public void Write(TProtocol oprot) {
// generated code for Write() method
}
public override string ToString() {
// generated code for ToString() method
}
}
This is what Thrift expects.
If below is what your are doing then it should work. Check if you are doing this. Employee is a demo call here, you have to use your actual class.
Employee object_name= new Employee();
object_name.setAge(27);
object_name.setName("Test");
TSerializer serializer = new TSerializer(new TSimpleJSONProtocol.Factory());
String json = serializer.toString(object_name);

In JavaBean, what calls setter method?

I'm struggling with how the getter/setter methods are called in a Java Bean. I don't see examples of the tutorials (https://netbeans.org/kb/docs/web/jsf20-intro.html) calling the setter methods and yet the values are obviously set.
As a result, I'm having trouble making sure my setter methods are being called. For instance...
#Named(value = "someJavaBean")
#SessionScoped
public class someJavaBeanSerializable {
String webServiceResponse;
public void setWebServiceResponse() {
this.webServiceResponse = "Just a test";
}
public String getWebServiceResponse() {
this.setWebServiceResponse();
return this.webServiceResponse;
}
public someJavaBean() {
System.out.println("You are in someJavaBean");
}
}
It appears that I have to manually call setWebSErviceResponse() in order for the setter to run which is typical of other languages. I'm okay doing that, but based on what I've read, I'm not sure that is the correct way to do it.
Any help or clarification would be appreciated.
Thank you,
Java beans define behavior by convention:
A class has a default public constructor with no arguments to it (or, essentially, no constructor).
Class properties are accessed using the convention of getters and setters - namely getWebServiceResponse() and setWebServiceResponse(String response).
The only methods present in the bean are the methods to interact with the fields - that is, a setter and getter for each field. If you have a final field, then this would change (you would only be able to have a getter).
Not having a parameter in your setter violates this convention.
Also, it's bad style to call your setter inside of your getter - the idea behind a setter is that it only sets a field, and a getter only returns whatever value is inside of that field - even if it's null. I'd remove the call to your setter as well.
Lastly, public someJavaBean() is invalid - you may have meant to return void.
Your setter method needs a parameter:
public void setWebServiceResponse(String webServiceResponse) {
this.webServiceResponse = webServiceResponse;
}
Sorry to be dense. In the following code from the tutorial (https://netbeans.org/kb/docs/web/jsf20-intro.html), where is the setter called?
#ManagedBean (name="UserNumberBean")
#SessionScoped
public class UserNumberBean implements Serializable{
Integer randomInt;
Integer userNumber;
String response;
public String getResponse() {
if ((userNumber != null) && (userNumber.compareTo(randomInt) == 0)) {
//invalidate user session
FacesContext context = FacesContext.getCurrentInstance();
HttpSession session = (HttpSession) context.getExternalContext().getSession(false);
session.invalidate();
return "Yay! You got it!";
} else {
return "<p>Sorry, " + userNumber + " isn't it.</p>"
+ "<p>Guess again...</p>";
}
}
public Integer getUserNumber() {
return userNumber;
}
public void setUserNumber(Integer userNumber) {
this.userNumber = userNumber;
}
/**
* Creates a new instance of UserNumberBean
*/
public UserNumberBean() {
Random randomGR = new Random();
randomInt = new Integer(randomGR.nextInt(10));
System.out.println("Duke's number : " + randomInt);
}
}

How to send JSON object to rest webservice?

I have a rest webservice at http://localhost:8600/rest/student/details which will update the details of student into database. I have to send the details as JSON format in method post.
The below is the method to generate that json message
private void createOrUpdateStudent(WebResource service) {
Gson gson = new Gson();
StudentImpl student= new StudentImpl ();
student.setId(6);
student.setName("Godwin");
student.setSex("Male");
StudentView view = new StudentView(student);
System.out.println("::::::"+service.path("/rest/student").path("/details").type("application/json").post(ClientResponse.class, gson.toJson(view)));
}
where studentView class is as below.
#XmlRootElement(name="clusterZipcode")
public class StudentView {
public Integer id;
public String name;
public String sex;
public StudentView() {}
public StudentView(StudentImpl student) {
this.id = student.getId();
this.name = student.getName();
this.sex = student.getSex();
}
while sending like above i am getting an error stating Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Column 'Name' cannot be null
Is i am passing the json values correctly or if there is an alternate method to send the json message please suggest me.
I cannot see on your post where are you doing the call to the database. All I can see is that you are creating a Student and then, from there, creating a view (assuming this method is being called). The error you are getting is related to the fact that, at some point, you are calling the database to enter a new row in (probably) your student Model. If you have got hibernate, can you make sure that you are not calling .save or .update at any point between the call you get for the student and before you call setName?

Change property name with Flexjson

I use FlexJson for serialization, the only problem is that it generates the field names lower case while I need them to start with upper case:
class Person
{
String name;
public String getName() { return name;}
}
When serialized the field is serialized as name, while I need it to be Name.
How can I specify the output field name? Is there some attribute I can put to specify the required serialization name?
You can achieve this by using a Custom Transformer. As per Flexjson page transformer is:
Responsible for deciding how to translate the passed in object to
JSON, making the appropriate calls on the JSONContext object to output
the JSON, and/or passing the object along the transformation process.
Flexjson has provided an abstract class AbstractTransformer for this purpose; Extend and override transform(Object object) to handle the transformation by yourself.
Pasted below is the code of FieldNameTransformer which I wrote for specifying the field name s manually:
public class FieldNameTransformer extends AbstractTransformer {
private String transformedFieldName;
public FieldNameTransformer(String transformedFieldName) {
this.transformedFieldName = transformedFieldName;
}
public void transform(Object object) {
boolean setContext = false;
TypeContext typeContext = getContext().peekTypeContext();
//Write comma before starting to write field name if this
//isn't first property that is being transformed
if (!typeContext.isFirst())
getContext().writeComma();
typeContext.setFirst(false);
getContext().writeName(getTransformedFieldName());
getContext().writeQuoted(object.toString());
if (setContext) {
getContext().writeCloseObject();
}
}
/***
* TRUE tells the JSONContext that this class will be handling
* the writing of our property name by itself.
*/
#Override
public Boolean isInline() {
return Boolean.TRUE;
}
public String getTransformedFieldName() {
return this.transformedFieldName;
}
}
Following is how to use this custom transformer:
JSONSerializer serializer = new JSONSerializer().transform(new FieldNameTransformer("Name"), "name");
where original field's name is 'name' but in json ouput it will be replaced with Name.
Sample out:
{"Name":"Abdul Kareem"}

Categories