All:
I am pretty new in Java. What I want to do is build a java data model object dynamically according to the CSV fields it reads in, like:
file1.csv
Name, Age, Email, Url
Allen, 30, allen#mail.com, http://allen.mail.com
Bob, 20, bob#mail.com, http://bob.mail.com
Firstly I read in the header, and according to the header, I want to create a class InfoModel which has those field names as its member variable.
Could anyone help? Thanks.
You could create the sourcecode dynamically, compile and load the class using the java API. But it would be pretty complicated to use the resulting class. You should simply use a hashmap for the variables in InfoModel and create the class before runtime. Would be simpler to use and more efficient.
You can create a corresponding Bean Class having Name, Age, Email, Url as member variable
Class Employee{
private String name;
private String age;
private String email;
private String url;
public Employee(String name,String age,String email,String url){
this.name=name;
this.age=age;
//and so on
}
// their getters and setters
}
// their getters and setters
}
Now as soon as you read the CSV lines after header , you can create Object of Employee Class
new Employee(name,age,email,url);
What I want to do is build a java data model object dynamically according to the CSV fields it reads in.
Ok, let's look at the CSV input again.
Name, Age, Email, Url
Allen, 30, allen#mail.com, http://allen.mail.com
Bob, 20, bob#mail.com, http://bob.mail.com
Here's the class that you want to generate.
package com.ggl.testing;
public class InfoModel {
private final String name;
private final int age;
private final String email;
private final String url;
public InfoModel(String name, int age, String email, String url) {
this.name = name;
this.age = age;
this.email = email;
this.url = url;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public String getEmail() {
return email;
}
public String getUrl() {
return url;
}
}
So, here is the main question you have to answer to generate the text of this class from the CSV file.
How do I determine what type of data is in the CSV file? In other words, how do I determine that Age is an int? How do I determine that Name is a String?
Once you've figured out the data types, you can output the text of the InfoModel class by using a lot of StringBuilders.
See my article, Writing Java Code that Writes Java Code, for an example of how to write a Java application that writes Java classes.
Just an idea... If the fields are limited, for example if you only need various combinations of fields, you could create an interface for each field (getter and setter) and then creaty a Proxy object for all of them, handling the data, for example, with an internal HashMap. This will get you an object that implements all of the interfaces, but of course, only in a very specific way.
Related
I have a POJO which has tens of fields, and I have to set all the fields' values.
How to avoid forgetting to set some field's value?
// POJO
public class Employee {
private Date birthday;
private String firstName;
private String lastName;
private String birthOfPlace;
// ...
// setters and getters
}
// Main class
public class MainClass {
public static void main(String[] args) {
Employee employee = new Employee();
// Call all the setters of Class Employee
employee.setFirstName("Jack");
employee.setLastName("Reed");
employee.setBirthOfPlace("Iceland");
// Oops, forget to call setBirthday()
}
}
As far as I know, there's no silver bullet solution to what you're asking for: at some point, you will have to either add a value to needed fields in your object, or write code that checks if you did it or not.
However, if you want to try anyway, there's a decent approache to making sure the most critical fields are present when needed: constructor parameters.
public Employee(String firstName, String lastName, Date birthday) {
this.firstName = firstName;
this.lastName = lastName;
this.birthday = birthday;
}
As long as you don't implement another constructor in this class, with this code, you'll be forced to provide a first name, last name, and date for each employee, meaning they'll never not be present (unless you pass null, but avoid doing that, it's arguably bad practice). If you need all your fields to be present, you'll need that many matching parameters in your constructor.
An alternative to this is to use an embedded Builder.
Use inner Builder class inside your class with constructor with required parameter(s), e.g. firstName:
public static class Builder {
private String firstName;
private String lastName;
public Builder(String firstName) {
this.firstName= firstName;
}
public Builder lastName(String lastName) {
lastName = lastName;
return this;
}
Make sure you can create an object only through the Builder
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'm trying to parse JSON using Retrofit and Gson, but I need to map one JSONfield
's value to multiple JAVA fields inside bean class.
Here is an example code:
class A{
#SerializedName("name");
private String name;
#SerializedName("name");
private String fullName;
}
This is the error I'm seeing: class A declares multiple JSON fields named name. Is there any way to do this?
Update: Please avoid suggesting removing one field from the bean or making changes into getter and setter. The project is huge, and the field is being used later in many other cases, so I don't want to mess with the structure. The question is pretty much clear and on the point.
No need to declare JSON for fullname use name value with fullname in setter gatter.
class A{
#SerializedName("name");
private String name;
private String fullName;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getFullName() {
return name;
}
public void setFullName(String fullName) {
this.name = fullName;
}
}
See below code for example:
public enum Employees {
BOB("Bob Barker", "BB", 100);
private String fullName; //are these better accessed through public or getFullName() below?
private String initials;
private String age;
Employees(String fullName, String initials, int age) {
this.fullName = fullName;
this.initials = initials;
this.age = age;
}
public String getFullName() {
return fullName;
}
//etc ...
}
Which method of accessing more correct or more memory efficient?
You cannot access the fullName through a static method. They are instance fields.
Your code is correct. You may wish to mark your String fields as final and rid yourself of the setXXX methods (since Enum values are traditionally immutable).
I would always make enum fields final, which then removes the utility of a setter. The enum instance is publicly shared and it is expected to be immutable by most sensible client code.
As far as the getter is concerned, that's up to your personal taste, although convention has it to add a getter and make the field private. So your taste has to be "strong".
use a getter its the convention ... and you won't get any nasty surprises if you at a later date use the enum within jstl/el which relies on the bean specification of using getters/is.
I think you are misunderstanding the concept of enums. An enum is a shared instance that does not change. What you describe is a regular mutable Java object. So the first thing you should do is switch from enum to class:
public class Employee {
private String fullName;
private String initials;
private String age;
public Employee(String fullName, String initials, int age) {
this.fullName = fullName;
this.initials = initials;
this.age = age;
}
public String getFullName() {
return fullName;
}
//etc ...
}
Then use your class like a regular class:
Employee bob = new Employee("Bob Barker", "BB", 100);
Edit
You have removed your setter now, but still, this still does not look like an enum to me.
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))