Calling a constructor without hard coding parameters (coupling) - java

I have a method which creates a new object Student and adds it to an array list studentRegister:
public void addStudent(String name, String age)
{
studentRegister.add(new Student(name, age));
}
it calls the Student class constructor here:
public Student(String name, String age)
{
this.name = name;
this.age = age;
}
This works but it is bad for maintainability as i have to change any additional parameters in both the Student class and the addStudent method. How do I input the parameters at the addStudent stage without having them harcoded in the addStudent method?

just do this:
public void addStudent(Student s)
{
studentRegister.add(s);
}
And in constructer/ other methods you can call the above method as below:
public Student(String name, String age)
{
this.name = name;
this.age = age;
addStudent(this); //here is the call to the above method
}

You should pass a student object - Instead of the two values.
public void addStudent(Student student)
{
studentRegister.add(student);
}

Using
public void addStudent(final Student student) {
studentRegister.add(student);
}
is the better aproach.
Maybe you're looking for a simpler way to build the object. e.g. using chain setters:
public class Student {
private String name;
private String age;
private String address;
public String getName() {
return name;
}
public Student setName(String name) {
this.name = name;
return this;
}
public String getAge() {
return age;
}
public Student setAge(String age) {
this.age = age;
return this;
}
public String getAddress() {
return address;
}
public Student setAddress(String address) {
this.address = address;
return this;
}
}
So, would then:
Student student = new Student().setName("User")
.setAge("30")
.setAddress("New York");
Another way for build the object with normal setters:
Student student = new Student(){{
setName("User");
setAge("30");
setAddress("30");
}};

Related

How to invoke method on a specific definition of a class using reflection?

I am trying to pull a field via reflection that is an array of the below class.
package com.api.Person
public class Person {
private String name;
private int age;
public Person() {
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package com.client.Client
public class Client{
...
People[] peoples;
...
}
I know how to get the field I am looking for and declare my methods. So below, obj would be my People[] and methodgetAge and methodsetAge are two methods I have defined that act on a Person class. How do I take my obj and loop through it to get individual People and call methodgetAge on each person?
Class<?> mainClass = cl.loadClass("com.client.Client");
Class<?> peopleClass = cl.loadClass("com.api.Person");
Field allPersons = mainClass.getDeclaredField("peoples");
allPersons.setAccessible(true);
Object obj = allPersons.get(mainClass);
Method methodgetAge = peopleClass .getDeclaredMethod("getAge");
Method methodsetAge = peopleClass .getDeclaredMethod("setAge", int.class);

Calling an object arraylist from another class and iteration through it

I have a problem accessing the arraylist I created in a class. I tried going through the answers of questions similar to mine but unfortunately I was unable to solve the problem.
So I have two classes Student and Person and I want to iterate through the arraylist of Person in the class Student. (The code doesn't really make sense, I know. I just want to understand).
I tried two approaches :
1) creating a variable of type Person in Student class and calling the get method from person class.
2) creating a get method in the class person that returns arraylist.
Both are not working properly when i tried to call the isHere method in the main method.(false was printed instead of true)
I think my two approaches intialise a new array of type Person and not call the arraylist to which elements are already added. How can solve this?
import java.util.ArrayList;
public class Student {
private Person p;
private String name;
private int age;
private String address;
public Student() {
}
public Student(String name, int age, String address) {
this.name = name;
this.age = age;
this.address = address;
}
public boolean isHere(String name) {
p = new Person();
// I also tried for(Person per : p.getList)
for (Person per : this.getL()) {
if (per.getName().equals(name)) {
System.out.println("hi");
return true;
}
}
return false;
}
public ArrayList<Person> getL() {
return p.getList();
}
public Person getP() {
return p;
}
public void setP(Person p) {
this.p = p;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
The Person class:
import java.util.ArrayList;
public class Person {
private String name;
private ArrayList<Person> list = new ArrayList<Person>();
Person() {
}
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ArrayList<Person> getList() {
return list;
}
public void setList(ArrayList<Person> list) {
this.list = list;
}
public void add(String name) {
list.add(new Person(name));
}
}
The statement p = new Person() in your isHere(..) method is creating a new Person object. When that Person object is created, the name in object p will be null and the list will be empty. So the for loop is never executed as the list is empty and hence it returns false.
If you ever want your code to run, you should not create the Person object and then immediately iterate through it because it will have nothing. You have to either add something to it or use a Person object which you believe will be populated before you run the isHere(..) method

PlayFramework Attempted to serialize java.lang.Class

I am trying to integrate gson in my Play! 2.x. I am using gson & jongo and facing this error : http://hastebin.com/agewopocen.bash
Here is my model class:
public class Person extends MongoModel<Person>
{
ObjectId _id;
String name;
int age;
public Person()
{
super(Person.class, "person");
}
public Person(String name, int age)
{
super(Person.class, "person");
this.name = name;
this.age = age;
System.out.println();
}
#Override
public Person setModel()
{
return this;
}
#Override
public ObjectId getId()
{
return null;
}
public void setName(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public String toJson()
{
return new GsonBuilder().create().toJson(this);
}
#Override
public String toString()
{
return new Gson().toJson(this);
}
}
I don't know what a "TypeAdapter" is (mentioned in the error log in the above link) and I am sure that we can get this working without using it. But, I dont know what I am missing.
Here is the code I tried (without Play, in regular Java) and it works.
public class Test
{
public static void main(String[] args)
{
Person nfe = new Person(10, "nfe");
String s = new Gson().toJson(nfe);
System.out.println(s);
}
public static class Person {
int age;
String name;
public Person(int age, String name)
{
this.age = age;
this.name = name;
}
public int getAge()
{
return age;
}
public void setAge(int age)
{
this.age = age;
}
public void setName(String name)
{
this.name = name;
}
}
}
Output :
{"age":10,"name":"nfe"}
Can someone help me in fixing this?

How to modify the already built object in Java, when the Object is built using Builder Pattern?

I have built (Using Builder Pattern) an Employee object with three fields Name, Age and Gender.
public class Employee {
private String name;
private String age;
private String gender;
// Constructor
private Employee(Builder builder) {
this.name = builder.name;
this.age = builder.age;
this.gender = builder.gender;
}
// Employee Builder
public static class Builder {
private String name;
private String age;
private String gender;
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(String age) {
this.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
}
// Getters
public String getName() {
return name;
}
public String getAge() {
return age;
}
public String getGender() {
return gender;
}
}
Now in the Following Class I have built my Employee Object,
public class TestEmployee {
public static void main(String[] args) throws IOException {
Employee employee = new Employee.Builder().age("23").gender("Male").name("John").build();
System.out.println("Name : " + employee.getName());
System.out.println("Age : " + employee.getAge());
System.out.println("Gender : " + employee.getGender());
}
}
How can I modify the Age of the Employee "John" by breaking the already built employee object?
FYI : I don't want to have Setters in my Employee object.
You want to modify an immutable object. Do you see the problem there?
Either add setters (or any methods that mutate the state) or accept that the object is immutable.
You can of course create a new object based on the values of the old one, but it won't be the same object then.
Build another one using Copy-On-Write (reuse existing fields but change age).
Employee.Builder()
.age(employee.getAge() + 1)
.gender(employee.getGender())
.name(employee.getName())
.build();
Keep in mind, it will be another object.
ahh I was also trying to solve my problem with this approach and ironically I stumbled upon this question. I understand the challenge here, we are trying to modify an object with same builder setters but doing so we'll end up with an new object.
I figured out that there is a solution, so after approx 5yrs here's my answer LOL(to someone who's gonna end up here)
first, instead of creating duplicate properties of OuterClass in inner static Builder class. *declare an instance of outer class in Builder class. which means your build() method will return that instance.
this *declaration of instance is intended, as I am planning to create it internally or gonna ask for its memory from outside.
public class Employee {
private String name;
private String age;
private String gender;
public Static Builder builder()
{
return new Builder();
}
public Static Builder modifier(Employee employee)
{
return new Builder(employee);
}
// Employee Builder
public static class Builder {
private Employee employee;
public Builder(Employee employee)
{
this.employee = employee;
}
public Builder()
{
this.employee = new Employee();
}
public Builder name(String name) {
this.employee.name = name;
return this;
}
public Builder age(String age) {
this.employee.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Employee build()
{
return this.employee;
}
}
// Getters
public String getName() {
return name;
}
public String getAge() {
return age;
}
public String getGender() {
return gender;
}
}
notice the tweak here, I introduced a modifier that takes Employee object and further allows client to modify it with Builder pattern.
So your client will use it like this...
to create new Employee
Employee employee = Employee.builder().name("abc).age(20).build();
to modify same instance
Employee.modifier(employee)
.name("xyz")
.build();
If you don't want to put setters (and make Employee mutable) you can't modify age of john... instead of this, what you can do is:
employee = new Employee.Builder()
.age("21")
.gender(employee.getGender())
.name(employee.getName())
.build();
If you don't want setters or public non-final fields, then you can add an extra constructor to the builder which will cause an initial state matching the instance, but with the builder setters available. This won't modify the original object, but create a new one based on it.
public static class Builder {
private String name;
private String age;
private String gender;
public Builder(Employee employee) {
this.name = employee.getName();
this.age = employee.getAge();
this.gender = employee.getGender();
}
public Builder name(String name) {
this.name = name;
return this;
}
public Builder age(String age) {
this.age = age;
return this;
}
public Builder gender(String gender) {
this.gender = gender;
return this;
}
public Employee build() {
return new Employee(this);
}
}
You can then use it as following.
Employee employee = new Employee.Builder().age("23").gender("Male").name("John").build();
Employee employee2 = new Employee.Builder(employee).name("Jane").build();

constructor error

I was told that when creating a new object, it needs to have the same parameters as its constructor. Ive tried, but i still get these error. cannot find symbol s1.getCourse s1.getName s1.getAge. and also an invalid constructor error. heres my code
public class Person{
private String name;
private int age;
public Person(String name, int age){
this.name=name;
this.age=age;
}
public String getDetails(){
return "Name: " + name + "Age: " + age;
}
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public class Student extends Person{
private String course;
public Student(String name, int age,String course){
super(name,age);
this.course = course;
}
public String getDetails(){
return super.getDetails()+"Course: "+ course;
}
public void setCourse(String course){
this.course=course;
}
public String getCourse(){
return course;
}
public String getName(){
return name;
}
}
public String getAge(){
return age;
}
}
TestPerson
student++;
String name=array[0];
int age=Integer.parseInt(array[1]);
String course=array[3];
Student s1= new Student(name,age,course);
System.out.println("name "+s1.getName());
System.out.println("age "+ s1.getAge());
System.out.println("course: " + s1.getCourse());
}
}
For more Detail can u provide Person class.
You have not provided the name and age attribute in student class.
if all this is present in super class then also When u call the s1.getName() method it will call from student class. because it present in sub class i.e student

Categories

Resources