I am using Boon JSON and I'd like to change the name of a field on a class that is being generated from JSON.
I just want to change
{"first_name": "Cristine", "last_name": "McVie"}
So it maps to the Java fields:
String firstName;
String lastName;
I've already got everything working (ie, if I use camel-case in the JSON, the object is created properly.
I've tried the #JsonPropery and (based on the suggestion in comments) the #Named annotations on the class, like so:
public class Person {
#Named("first_name")
private String firstName;
#Named("first_name")
public String getFirstName() {
return firstName;
}
#Named("first_name")
public void setFirstName(String firstName) {
this.firstName = firstName;
}
Just for edification, this is why I didn't see #JsonProperty working at first. This app is running in Eclipse debug mode, and I was trusting Eclipse to redeploy the updated code, but adding an annotation is apparently NOT enough to trigger the update. Had to restart the app to pick it up.
You need to add either a SerializedName annotation (like GSON) or aJsonProperty annotation (like Jackson) to the fields, like so:
import org.boon.json.annotations.JsonProperty;
import org.boon.json.annotations.SerializedName;
public static class Person {
#SerializedName("first_name")
String firstName;
#JsonProperty("last_name")
String lastName;
}
You can see another example in the documentation.
Related
So I am wondering what the best way to process an edit request based on a user role.
Say I have the following PostMapping:
#PostMapping(value = "/edit")
public ResponseEntity<String> editIoc(#RequestBody GeneralPojoAllFields editRequest)
the GeneralPojoAllFields looks like this:
public class GeneralPojoAllFields {
private String firstName;
private String lastName;
private String onlyAdminCanEditField;
}
This is the pojo the the admin will be able to use and that will eventually get mapped into the entity class to be saved to the database. However, if we have a regular user who wants to edit it and hypothetically they aren't restricted in the UI would that design work? What I am currently thinking is I would have a user pojo like so:
public class UserPojo {
private String firstName;
private String lastName;
}
After the request mapping comes we check if the user is either regular user or an admin. If it is a regular user we just map the GeneralPojoAllFields to the UserPojo and it wont map over the onlyAdminCanEditField and continue from there.
Is there a better way to do this?
First, your backend should be as independent of the UI as possible. So, access control in UI is a good to have design, but you should not depend upon it.
Now, coming back to your question, yes you can use SecurityContextHolder to find out if the user if regular user/admin. However, if its possible, I would suggest making two controllers, one for admin and one for regular user. Use #PreAuthorize on the admin controller to restrict access. Having two separate controllers will increase readability of your code tremendously.
Additionally, you can call the same service class method from both the controllers. And since you already have two POJO classes, you can use them in #RequestBody and let Spring take care of the mappings for you.
Well, it depends what you think a better way would be. It also depends a bit on your data source. But as there is no information on that here, I would suggest that a better way to do yours is by inheritance.
Make UserPojo the super class and GeneralPojoAllFields extend that class.
UserPojo.java:
public class UserPojo {
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public UserPojo() {}
public UserPojo(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
GeneralPojoAllFields.java:
public class GeneralPojoAllFields extends UserPojo {
private String onlyAdminCanEditField;
public String getOnlyAdminCanEditField() {
return onlyAdminCanEditField;
}
public void setOnlyAdminCanEditField(String onlyAdminCanEditField) {
this.onlyAdminCanEditField = onlyAdminCanEditField;
}
public GeneralPojoAllFields() {}
public GeneralPojoAllFields(String firstName, String lastName, String onlyAdminCanEditField) {
super(firstName, lastName);
this.onlyAdminCanEditField = onlyAdminCanEditField;
}
}
App.java:
public class App {
public static void main(String[] args) {
UserPojo up1 = new UserPojo();
up1.setFirstName("MyFirstName");
up1.setLastName("MyLastName");
GeneralPojoAllFields gpaf1 = new GeneralPojoAllFields();
gpaf1.setFirstName("MyFirstName");
gpaf1.setLastName("MyLastName");
gpaf1.setOnlyAdminCanEditField("yes");
}
}
I am having an object as below
public class Employee{
String firstName;
String lastName;
String address;
String phoneNumber;
List<Contacts> Contacts;
}
public class Contacts{
String name;
String Address;
String phoneNumber;
}
Now considering the Employee object is set with values inside the application and when I try to convert the object say with name empObject(which has all values) into JSON as below
ObjectMapper mapper= new ObjectMapper();
String employeeObjToJSON =mapper.writeValueAsString(empObject);
System.out.println("JSON employee Object" +employeeObjToJSON)
I get the values
{"firstName":"Sawyer","lastName":"Ford","phone":"4555454553", "address": "SNJFJJFJ", "contacts":[{"phoneNumber": "122333"},{"phoneNumber":"122222"}]}
Only the phone number is printed for the Inner Object. How should I get the complete object in JSON
Your class structure seems a little off. Why would the Employee class have a list of contacts as String, rather than a list of Contact objects?
I would suggest you change your Employee class like this:
public class Employee {
String firstName;
String lastName;
String address;
String phoneNumber;
List<Contact> contacts;
}
public class Contact {
String name;
String address;
String phoneNumber;
}
Using this class structure you should not have any problems mapping them to JSON using ObjectMapper.
Edit:
Regarding the null fields not being displayed, as I wrote in the comment, by default Jackson should serialise them and you should see them in the response.
If that is not the case, it might be that this serialisation feature has been overridden somewhere... try setting the following config to your object mapper and see if it works: mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS).
Alternatively, you can also use the Jackson annotation #JsonInclude(JsonInclude.Include.ALWAYS) on your Employee class and Contact class like ibenjelloun suggested in his/her answer.
Did you try the following class annotation :
#JsonInclude(JsonInclude.Include.ALWAYS)
According to the javadoc, it's the default value, maybe it is overwritten somewhere in your code ?
I am following this spring guide:
https://spring.io/guides/gs/accessing-mongodb-data-rest/
Everything is perfect, however if I want to POST a document with manual id, I am not able to do that.
Here is what all I have done:
I inserted one document from Mongo shell by the command db.person.insert({"_id": "111111", "firstName" : "Vikas", "lastName" : "Prasad"});
This works fine and if I do a GET at http://localhost:8080/people from Postman, I can see the person document with id 111111 in the response having self href as http://localhost:8080/people/111111
But if I am sending a POST request from Postman at http://localhost:8080/people with body as {"_id": "222222", "firstName" : "Aadish", "lastName" : "Patodi"}, the document is getting inserted with an auto id instead of 222222. Because of which obviously I cant access this docuemnt by doing a GET at http://localhost:8080/people/222222 unlike the case when I used insert() from the shell to insert a document with manual id. Instead I have to hit a GET at http://localhost:8080/people/57bc29ada3fab115cc9b546b to fetch this second document.
Just to check if I am POSTing the {"_id": "222222", "firstName" : "Aadish", "lastName" : "Patodi"} again, its getting inserted again at a new auto generated id: http://localhost:8080/people/57bc2bdaa3fab115cc9b546c. It means MongoDB is not even looking at the _id, else it must have thrown duplicate key error.
I tried searching various sources. All I can found is an implementation of the data access code separately in JAVA at back end and calling respective MongoDB methods.
My question is:
Just like in the given tutorial they are performing every operation without defining any JAVA back end code for data access from MongoDB for auto id documents, is there a way to do the same for manual id documents?
Or just for this one use case I have to implement the data access code at the back end?
I am using CorsFilter to handle cross origin requests.
Edit:
Below is the Person class:
package hello;
import org.springframework.data.annotation.Id;
public class Person {
#Id private String id;
private String firstName;
private String lastName;
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
I have tried:
-> adding getter and setter for id attribute
-> renaming id to employeeNumber
-> renaming id to employeeNumber and adding getter and setter for employeeNumber
None of the above three solved the issue.
as discussed on the comment, looks like your _id field is not mapped correctly. Can you check if the _id is mapped correctly in the pojo ?
Finally, I got it working by renaming id with _id and adding getter and setter for the same in the Person class.
package hello;
import org.springframework.data.annotation.Id;
public class Person {
#Id private String _id;
private String firstName;
private String lastName;
public String get_id() {
return _id;
}
public void set_id(String _id) {
this._id = _id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
I created a simple project with GAE and i put in my package 'model' the PMF.java (Persistence Manager Factory Class) and a class (Employee.java) that i can show you here:
#PersistenceCapable
public class Employee {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private String firstName;
#Persistent
private String lastName;
#Persistent
private Date hireDate;
public Employee(String firstName, String lastName, Date hireDate) {
this.firstName = firstName;
this.lastName = lastName;
this.hireDate = hireDate;
}
// Accessors for the fields. JDO doesn't use these, but your application does.
public Key getKey() {
return key;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public Date getHireDate() {
return hireDate;
}
public void setHireDate(Date hireDate) {
this.hireDate = hireDate;
}
}
When i click on Google->Generate Cloud Enpoint Client Library, i receive the following error message:
Error in Generating API: this project does not have cloud endpoint classes. What does it mean? Thank you so much
You have done the first part i.e. created your model.
When you try to generate the Cloud Endpoint Client Library, the tool is look for Java classes that are annotated with the #API annotation, so that it knows which classes are your endpoints.
What you should try is the following series of steps :
Create a new Project and add your model i.e. Employee
Generate the Endpoint classes for Employee by simply right clicking on the class in the Project and selecting Google -> Generate Cloud Endpoint class. This will generate the Endpoint class EmployeeEndpoint along with PMF. java.
Now, right-click on the project and select Google -> Generate Cloud Endpoint Client Library and you should be good since the tool will find the Endpoint class (EmployeeEndpoint) that has been annotated correctly.
Hypothetically, lets say I have a domain object called Person. It looks like such:
public class Member {
private final String firstName;
private final String lastName;
private final String email;
private final String password;
public Member(String firstName, String lastName, String email, String password) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
}
I also have a MemberRepository interface that defines basic CRUD and some other sugary methods.
Now lets say I want to persist this domain object in a MongoDB instance using Morphia. I've created my MorphiaMemberRepository implementation but what I'm unsure of is how to store the domain object with as little mess as possible.
Any Morphia users would know that I'd need to create an ID field of type ObjectId and annotate it with #Id. Additionally I'd need to annotate the class with #Entity("members"). I don't necessarily want to clutter up my nice domain object with the Morphia/MongoDB specific annotations.
So...fellow stackers, what should I do to keep this implementation as clean as possible?
That is the requirement for Morphia (at least the #Id one). Annotations do not require changing the way you use your object or serialization. They are just extra metadata which most programs ignore; they are harmless.
If you have a unique field then you don't need to add any new ones, just mark that with #Id and be done with it.
If you really don't want to do any of this, you can manually create the metadata in morphia to deal with your classes, but that will be much more work as that process is not exposed via any external configuration format.
Suppose there is IMember so Member implements IMember. Getter methods are defined in IMember.
Another class MorphiaMember implements IMember is annotated as necessary and has ID field (id is not always ObjectId).
Each class has a factory method
public static Member from(IMember mi) { ... }
so typical workflow will be:
MemberRepository repo = ...
Member m = Member.from(repo.get(some_id))
...
Member m2 = ...
repo.save(MorphiaMember.from(m))