JSON with spaces in variable names [duplicate] - java

This question already has answers here:
How to parse with GSON when identifier has space in name
(2 answers)
Closed 6 years ago.
I have a JSON with spaces in the variable names something like the following:
{
"First Name":"John",
"Last Name":"Smith"
}
Since Java doesn't allow spaces in variable names I'm trying to see if Gson has a provision to parse this into First_Name or FirstName or something of that sort so I can use First_Name or FirstName as the variable name in my Java class to represent this data.
Is there a way to do it or will I need to make a local copy of the JSON and run a String parser through the JSON file to rename the variables and then pass it on to Gson to do the rest?
Any ideas?
Note: This JSON is being sent by a third-party API I am using, not my own creation. So while I wish I could tell them about proper naming conventions, that isn't where I would like to spend my time :)

Have you tried using field naming support. My first guess is it sshould work with spaces in the name (https://sites.google.com/site/gson/gson-user-guide#TOC-JSON-Field-Naming-Support). Something like below should work.
Tried the below , it works (I don't agree with the naming , but it works)
import com.google.gson.Gson;
public class SOMain {
public static void main(String[] args) throws Exception{
Gson gson = new Gson();
String json = "{\"First Name\":\"John\",\"Last Name\":\"Smith\"}";
Employee employee = gson.fromJson(json, Employee.class);
System.out.println(employee);
}
}
import com.google.gson.annotations.SerializedName;
public class Employee {
#SerializedName("Last Name")
public String lastName;
#SerializedName("First Name")
public String firstName;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
#Override
public String toString() {
// TODO Auto-generated method stub
return "Employee with first name " + firstName + " and last name " + lastName ;
}
}

First of all, name your variable firstName in your java code, see Variable naming conventions in Java?
Second, to change field names with Gson: here is a great tutorial: http://www.javacreed.com/gson-annotations-example/

Related

POJO to JSON conversion not working for String variable starting with "is"

String variable - "isInitial" in below example is not getting converted into JSON. Is it possible to generate JSON structure for isInitial variable without modifying the EmployeePOJO class?
PS: converting the getter method to getIsInitial works.
Please find below POJO class used for generating the JSON:
public class EmployeePOJO {
private String firstName;
private String lastName;
private String isInitial;
private boolean isFirstNameAvailable;
private boolean hasLastNameAvailable;
private String hasHouse;
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 String isInitial()
{
return this.isInitial;
}
public void setInitial(String pInitial)
{
this.isInitial = pInitial;
}
public String getHasHouse() {
return hasHouse;
}
public void setHasHouse(String hasHouse) {
this.hasHouse = hasHouse;
}
public boolean isFirstNameAvailable() {
return isFirstNameAvailable;
}
public void setFirstNameAvailable(boolean firstNameAvailable) {
isFirstNameAvailable = firstNameAvailable;
}
public boolean isHasLastNameAvailable() {
return hasLastNameAvailable;
}
public void setHasLastNameAvailable(boolean hasLastNameAvailable) {
this.hasLastNameAvailable = hasLastNameAvailable;
}
}
Please find below main logic for POJO conversion:
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
public class JacksonPojoToJson {
public static void main(String[] args) throws IOException {
// Create ObjectMapper
ObjectMapper mapper = new ObjectMapper();
EmployeePOJO employeePOJO = new EmployeePOJO();
employeePOJO.setFirstName("FIRST NAME");
employeePOJO.setFirstNameAvailable(true);
employeePOJO.setLastName("last name");
employeePOJO.setHasLastNameAvailable(true);
employeePOJO.setInitial("true");
// Convert object to JSON string
String json = mapper.writeValueAsString(employeePOJO);
System.out.println(json);
}
}
Bad naming conventions. If you are using IDE let the IDE generate the getters and setters for you.
The isInitial method can be used as getter for a Boolean variable. Not a String variable.
So you can fix your POJO class (https://en.wikipedia.org/wiki/Plain_old_Java_object)
or you can use the #JsonProperty annotation (https://fasterxml.github.io/jackson-annotations/javadoc/2.8/com/fasterxml/jackson/annotation/JsonProperty.html)
Use Lombok maven dependency for generate automatic getter & setter.
You have to use the correct naming of getters and setters for your variable for example:
private String isInitial;
For the above variable getter setter should be:
public String getIsInitial()
{
return this.isInitial;
}
public void setIsInitial(String isInitial)
{
this.isInitial = isInitial;
}
Note: I don't know your use case but name like isXXXX used for getters of boolean variables.
I would recommend using Lombok's #Getter and #Setter annotations to auto-generate your getter and setter methods. Using these, you will not run into issues with naming conventions etc.
Please see the following URL for more information:
https://projectlombok.org/features/GetterSetter
#Loizos - Thanks a lot for the suggestion #JsonProperty, it worked fine. I was looking at a solution without modifying the class - EmployeePOJO (since it is legacy code which we dont want to touch).
I got this resolved by using Mixins, which does not require modification in EmployeePOJO file.
Sample code which worked for me:
public interface EmployeePOJOMixIn {
#JsonProperty("isInitial")
public abstract String isInitial();
}
Then adding this Mixin to mapper (this will vary based on whether you are using fasterxml or codehaus)
https://www.leveluplunch.com/java/tutorials/024-modifying-fields-external-domain-jackson-mixin/ and https://medium.com/#shankar.ganesh.1234/jackson-mixin-a-simple-guide-to-a-powerful-feature-d984341dc9e2 are good sites which I referred for the solution.
The reason for this is that the setters/getters for boolean variables do not follow the pattern setVariableName/getVariableName.
You could see in your own code that it is like this:
public String isInitial()
{
return this.isInitial;
}
public void setInitial(String isInitial)
{
this.isInitial = isInitial;
}
Quick fix would be to create the setters/getters for boolean variables manually.
This (setter/getter creation issue) usually happens in eclipse, but I think IntelliJ handles this right.

Q: Player(class) java

Have to code a player class in java eclipse following these requirements
a) The Player class should have a default constructor and two custom constructors - one
that accepts a Name object, and another that accepts both a Name and PairOfDice object.
b) There should be get and set methods for its Name and a get method for PairOfDice. It
should have a method called rollDice and getDiceScore that both simply delegate to the
PairOfDice class, which already has this functionality. You should also have an
appropriate toString() method.
c) Add a further void method setFullPlayerName(String) that accepts a single String
argument (e.g. “Joe Bloggs”) and then uses this to set the first and family name
individually by extracting the relevant information and then calling the respective setter
methods of the Name class.
So far I have this
public class Player {
//Fields of the app
private String firstName;
private String lastName;
private Die red;
private Die blue;
//PlayerName and dice pair Default Constructor
public Player() {
firstName = "";
lastName = "";
red = new Die();
blue = new Die();
}
public Player(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public Player(String firstName, String lastName,Die red,Die blue) {
this.firstName = firstName;
this.lastName = lastName;
this.red = red;
this.blue = blue;
}
// Methods
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setlastName(String lastName) {
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getlastName() {
return lastName;
}
#Override
public String toString() {
return "PairOfDice:[red=" + red + ", blue=" + blue + "]";
}
public void rollDice() {
red.roll();
blue.roll();
}
public int getDiceScore() {
return red.getScore() + blue.getScore();
}
public Die getRed() {
return red;
}
public Die getBlue() {
return blue;
}
public String setFullName() {
if (firstName.equals("") && lastName.equals("")) {
return "";
} else {
return firstName + " " + lastName;
}
}
}
Is my code correct? if not what changes do i have to make to correct it
There are several problems:
Dice not Die: private Die red;
It's better to name your variable using a noun: private Dice redDice;
Should have a space after a comma: , Dice redDice, Dice blueDice
setFullName should accept 1 string and call setFirstName and setLastName to set the name
Example of implementation:
void setFullName(String fullName) {
/// split full name into lastName and firstName
setFirstName(firstName);
setLastName(lastName);
}
Everything seems fine, but I think you forgot to define the roll() function. Besides that, everything else seems fine :)
I see a couple of issues with this code:
a) The Player class should have a default constructor and two custom constructors - one that accepts a Name object, and another that accepts both a Name and PairOfDice object.
b) There should be get and set methods for its Name and a get method for PairOfDice. It should have a method called rollDice and getDiceScore that both simply delegate to the PairOfDice class, which already has this functionality. You should also have an appropriate toString() method.
If it's telling you that you need a Name object and a PairOfDice object, you can't just put in two Strings and two Dies and call that the same thing. You need to actually use the Name and PairOfDice classes.
c) Add a further void method setFullPlayerName(String) that accepts a single String argument (e.g. “Joe Bloggs”) and then uses this to set the first and family name individually by extracting the relevant information and then calling the respective setter methods of the Name class
Instead of setFullPlayerName, you made a method called setFullName that does not do what it's supposed to do. It's supposed to accept a String and return void, and instead it accepts no parameters and returns a String. It looks like a getter instead of a setter.
Let's get this straight: This portion of the code:
public String setFullName() {
if (firstName.equals("") && lastName.equals("")) {
return "";
} else {
return firstName + " " + lastName;
}
}
it's misleading due to the fact that the method name it's saying that it's setting the name, BUT you're returning the name instead
So change it to this:
public void setFullPlayerName(String name) {
String[] splitted = name.split(" ");
firstname = splitted[0];
lastname = splitted[1]
}
And now it's unnecessary to add the method setFullPlayerName
BUT I see that you may need a method to return a full name, so:
public String getFullPlayerName() {
return firstname + " " + lastname;
}
Hopefully that'll resolve your issue :D

Loading Java Builder Object from Yaml file

I have created a Bean Class using Builder Pattern and having issues creating an object from a yaml file.
Here is a sample class (Actual class is quite big, this is just an excerpt incase if you wanted to answer with an example):
public class ClientBuilder {
private final String firstName;
private final String lastName;
private final String displayName;
private ClientBuilder(Builder builder) {
firstName = builder.firstName;
lastName = builder.lastName;
displayName = builder.displayName;
}
public static class Builder {
private final String displayName; // Mandatory Attribute
public Builder( String displayName ) {
this.displayName = displayName;
}
private String firstName;
private String lastName;
public Builder setFirstName(String firstName) {
this.firstName = firstName;
return this;
}
public Builder setLastName(String lastName) {
this.lastName = lastName;
return this;
}
public ClientBuilder build() {
return new ClientBuilder(this);
}
}
#Override
public String toString() {
StringBuffer sbf = new StringBuffer();
sbf.append("New Company Object: \n");
sbf.append("firstName : " + this.firstName + "\n");
sbf.append("lastName : " + this.lastName + "\n");
sbf.append("displayName : " + this.displayName + "\n");
return sbf.toString();
}
}
I am using snakeyaml to load the file but any yaml api would work. Since the displayName is a mandatory param, I want to pass that value while creating the instance. The other params can be passed while creating the object but I would like the option to load them through yaml file.
I am able to load the yaml file if I use java bean. Is there a way to instantiate builder objects?
I tried:
InputStream input = new FileInputStream(new File("src/main/resources/client.yaml"));
Yaml yaml = new Yaml();
Builder builder = new Builder("Display Name");
builder = (Builder) yaml.loadAs(input, ClientBuilder.Builder.class);
ClientBuilder client = builder.build();
System.out.println(client.toString());
but I get following error:
Exception in thread "main" Can't construct a java object for tag:yaml.org,2002:com.xxx.xxx.xxx.ClientBuilder$Builder; exception=java.lang.NoSuchMethodException: com.xxx.xxx.xxx.ClientBuilder$Builder.<init>()
in 'reader', line 2, column 1:
firstName: "Jaypal"
SnakeYaml is a very powerful library & it provides support for creating instance based on constructor injection.
/**
* create JavaBean
*/
public void testGetBeanAssumeClass() {
String data = "--- !!org.yaml.snakeyaml.constructor.Person\nfirstName: Andrey\nage: 99";
Object obj = construct(data);
assertNotNull(obj);
assertTrue("Unexpected: " + obj.getClass().toString(), obj instanceof Person);
Person person = (Person) obj;
assertEquals("Andrey", person.getFirstName());
assertNull(person.getLastName());
assertEquals(99, person.getAge().intValue());
}
/**
* create instance using constructor arguments
*/
public void testGetConstructorBean() {
String data = "--- !!org.yaml.snakeyaml.constructor.Person [ Andrey, Somov, 99 ]";
Object obj = construct(data);
assertNotNull(obj);
assertTrue(obj.getClass().toString(), obj instanceof Person);
Person person = (Person) obj;
assertEquals("Andrey", person.getFirstName());
assertEquals("Somov", person.getLastName());
assertEquals(99, person.getAge().intValue());
}
Junit code sample can be viewed here.
So your code still holds good. You may need to change yaml content with proper format. Once done, you are all set.
The exception is about there not being a no-arg constructor in Builder, as you probably figured out.
What you could do is to allow no-arg constructor for Builder and add corresponding setter and getter for displayName to it. Then simply throw an exception in build() if displayName is not set (or provide a default value for it). The exception can be a runtime one, or you could make it clear and add an explicit throws.
While it is not the prettiest solution, it should work just fine. The fact that the Builder is created without a mandatory argument should not matter, as it is the ClientBuilder that needs to be constructed properly (as the factory/builder is used to ensure that each instance of whatever it is building is correct).
I have no way to access any yaml parsing tools for Java currently, but if there is any way I could improve my answer, let me know - I will be happy to do so.

Java: beginner help getting variable

This is for a school project. I have built a simple class with 3 string variables and a constructor to fill these fields.
public class Names {
String firstName;
String middleName;
String lastName;
public Names(String name){
System.out.println("Passed name is: " + name);
}
public void setFirstName(String name){
firstName = name;
}
public void setMiddleName(String name){
middleName = name;
}
public void setLastName(String name){
lastName = name;
}
public static void main(String []args){
Names drew = new Names("Drew");
drew.setFirstName("Drew");
drew.setMiddleName("Leland");
drew.setLastName("Sommer");
System.out.println(drew.firstName + " " + drew.middleName + " " + drew.lastName);
}
public getFirstName(String name){
}
public getMiddleName(String name){
}
public getLastName(String name){
}}
At the bottom where it is getFirstName, getMiddleName, getLastName I want to be able to pass something like getFirstName(drew) and have it return drew.firstName?
I am very new to java FYI.
These are "getter" methods to return the values of instance fields. drew is your current Names instance here, therefore if you call these methods on this instance, you'll receive the values you've set with your "setter" methods. And since you're calling them on a specific instance, you don't need to pass it as a method argument. That is why these getter methods are normally parameterless.
They should look like this:
public String getFirstName() {
return firstName;
}
public String getMiddleName() {
return middleName;
}
public String getLastName() {
return lastName;
}
Please note that I've added the corresponding return type (String), because the data type of each instance field is String.
Your println call in the main method would then look like this:
System.out.println(drew.getFirstName() + " " + drew.getMiddleName() + " " + drew.getLastName());
public String getFirstName() {
return this.firstName;
}
This will return the firstName of the object you call it on.
You can call it like this:
System.out.println(drew.getFirstName() + " " + drew.middleName + " " + drew.lastName);
You can then do the same thing for getMiddleName and getLastName.
Your get methods will be called by an instance of your Names class. When you create an instance of the class and assign it a variable name, just use that variable name to call the method and it will return the name for that instance.
//Instantiate the Names class
Names drew = new Names("Drew");
//Call methods to set the names
drew.setFirstName("Drew");
drew.setMiddleName("John");
drew.setLastName("Smith");
//Call methods to get the names
drew.getFirstName(); //Returns "Drew"
drew.getMiddleName(); //Returns "John"
drew.getLastName(); //Returns "Smith"
And, like others suggested, your get / set methods should be like this:
public void setFirstName(String n){
firstName = n;
}
public String getFirstName(){
return firstName;
}
as you said, "I want to be able to pass something like getFirstName(drew) and have it return drew.firstName"
so the impl is simple,
public String getFirstName(Names other) {
return other.firstName;
}

Pulling XML from a File for use in Java Program using XStream

I'm currently writing a text processing program in Java that needs to pull XML from an XML file and convert that into a Java object. I'm using what the quick tutorial on the XStream website suggested:
XStream xstream = new XStream();
Map<String, Integer> englishCorpusProbDist = (Map<String, Integer>)xstream.fromXML(xmlString);
where "xmlString" is the XML code. The only problem is that I have the XML in an XML file saved elsewhere on my computer, rather than as a string in my program. Is there a way to feed in the local address of the XML file into the .fromXML function and have it read the XML in the file, rather than directly feeding the XML itself into the function?
Any help would be much appreciated. Thanks in advance!
You just have to look for how you can create a Java String object from xml file, which you can pass to fromXML() method. Refer this link for more reference on SO, for how to create String from XML document.
Check out the other posts on Stackoverflow on how to read the contents from a file into a String with Java, e.g. this article.
Or you use the XStream.fromXML(File file) method, i.e.
XStream.fromXML(new File("myfile.xml"));
Try this working example
public class Person {
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;
}
}
And execute the below code
public static void main(String[] args) throws Exception{
XStream xstream = new XStream();
Person person = (Person)xstream.fromXML(new FileReader("a.xml"));
System.out.println(person.getFirstname());
}

Categories

Resources