String answer = question1?.question2?.answer
Is there a way (preferably in-built) to get the property of an object where both the following scenarios are covered:
If the object is null, return a null value for the attribute.
Returns null for an attribute if it doesn't exist in the object.
To top this, is there a way to chain such get operations for deeply nested attributes?
Java doesn't however Groovy does. When writing Groovy you can mix java right in with it. In Groovy you can do println company?.address?.street?.name
it's possible to obtain "similar" behavior(chain) but just with custom code ( not being something inbuild)
public class TestChain
{
public static void main(String args[])
{
TestChain tc = new TestChain();
Person p = tc. new Person();
p.setName("pName").getMsg().setAge(10).getMsg();
}
class Person
{
String name;
int age;
public Person setName(String name)
{
this.name = name;
return this;
}
public Person setAge(int age)
{
this.age = age;
return this;
}
public Person getMsg()
{
System.out.println(this);
return this;
}
public String toString()
{
return "name="+name+",age="+age;
}
}
}
Output:
name=pName,age=0
name=pName,age=10
Basically methods to be chained need to return current instance.
Related
As a task in my beginners course in object oriented programming, I must set two objects in my Partner class as "married".
This is my attempt at beginning:
public class Partner {
String name;
String partner;
public Partner(String name, String partner) {
super();
this.name = name;
this.partner = partner;
}
public String getPartner() {
return partner;
}
public void setPartner(Partner()) { //think i need the object here?
this.partner = partner; //however i don't know how
}
public String getName() {
return name;
}
public static void main(String[] args) {
Partner p1 = new Partner("Name1", idk);
Partner p2 = new Partner("Name2", idk);
}
}
My issue is that I don't know how to use the object in the setPartner method, if that's even the correct way to do it. It should also be possible to get a divorce from the other object by setting one of the objects' partner to null.
It should also make it so that the partners automatically register as married to eachother if one of them is set a married to the other. For example, if p1 is set as the partner of p2, p2 should automaticly be set as the parter to p1 as well.
Create two constructors: one with just name and another with name and partner (of type, Partner) so that you will have the flexibility to initialize an object with just name and then set its partner or initialize with name and partner (if the partner is known).
public class Partner {
private String name;
private Partner partner;
public Partner(String name) {
this.name = name;
}
public Partner(String name, Partner partner) {
this.name = name;
setPartner(partner);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setPartner(Partner partner) {
partner.partner = this;
this.partner = partner;
}
#Override
public String toString() {
String value;
if (partner != null) {
value = name + ", partner=" + partner.name;
} else {
value = name;
}
return value;
}
public static void main(String[] args) {
// Example 1
Partner p1 = new Partner("Name1");
Partner p2 = new Partner("Name2");
p1.setPartner(p2);
System.out.println(p1);
System.out.println(p2);
// Example 2
Partner p3 = new Partner("Name3");
Partner p4 = new Partner("Name4", p3);
System.out.println(p3);
System.out.println(p4);
}
}
Output:
Name1, partner=Name2
Name2, partner=Name1
Name3, partner=Name4
Name4, partner=Name3
Are you asking how to write setter methods ? Something like this
public void setPartner(String partner) {
this.partner= partner;
}
If you intend for a Partner object to have a pointer to another object of this class, you should change String partner to Partner partner.
You won't always have an initialized Partner object to use in the Partner constructor, so you have 3 options:
add another constructor which doesn't require an argument of type Partner
change the existing constructor
pass null as argument.
In any case, you'll have to initialize the partner field somewhere else.
That's where setters come in. The correct syntax for your setPartner function would be:
public void setPartner(Partner partner) {
this.partner = partner;
}
getPartner() function should be changed accordingly to return the correct type.
Your code in main() can then be something like this:
Partner p1 = new Partner("Name1", null);
Partner p2 = new Partner("Name2", p1);
p1.setPartner(p2);
It should also be possible to get a divorce from the other object by setting one of the objects' partner to null.
That is accomplished by using p.setPartner(null), where p is an object of type Partner. You might also want to set both objects partners to null instead of just one, for easier checking.
We use the builder pattern extensively in our code base, with built objects all having a toBuilder() method. I want to write a unit test that ensures that no fields have been forgotten in the toBuilder() methods, i.e., for any buildable object, I want to a test roughly like this
MyClass obj = getTestObjectWithRandomData();
assertEquals(obj, obj.toBuilder().build());
Now, I can fairly easy write a basic version of getTestObjectWithRandomData() that uses reflection to assign a bunch of values to the fields of any object. However, the snag is that build() often contains tons of validation checks that will throw exceptions if, for example, a certain integer isn't within a sane range. Writing a generalized version of getTestObjectWithRandomData() that conforms all those class-specific validation checks would be impossible.
So, how can I do what I want to do? I'm tempted to segregate the construction and validation code into different methods so that the test doesn't trip on the validation, but then that means that people have to remember to call validate() or whatever on objects after they create them. Not good.
Any other ideas?
How about using Lombok? Would that be an option for you? It will auto-generate the builder code and you'll never again have to worry about it.
https://projectlombok.org/features/Builder
Simply annotate your classes with #Builder
With Lombok
import lombok.Builder;
import lombok.Singular;
import java.util.Set;
#Builder
public class BuilderExample {
private String name;
private int age;
#Singular private Set<String> occupations;
}
Vanilla Java
import java.util.Set;
public class BuilderExample {
private String name;
private int age;
private Set<String> occupations;
BuilderExample(String name, int age, Set<String> occupations) {
this.name = name;
this.age = age;
this.occupations = occupations;
}
public static BuilderExampleBuilder builder() {
return new BuilderExampleBuilder();
}
public static class BuilderExampleBuilder {
private String name;
private int age;
private java.util.ArrayList<String> occupations;
BuilderExampleBuilder() {
}
public BuilderExampleBuilder name(String name) {
this.name = name;
return this;
}
public BuilderExampleBuilder age(int age) {
this.age = age;
return this;
}
public BuilderExampleBuilder occupation(String occupation) {
if (this.occupations == null) {
this.occupations = new java.util.ArrayList<String>();
}
this.occupations.add(occupation);
return this;
}
public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
if (this.occupations == null) {
this.occupations = new java.util.ArrayList<String>();
}
this.occupations.addAll(occupations);
return this;
}
public BuilderExampleBuilder clearOccupations() {
if (this.occupations != null) {
this.occupations.clear();
}
return this;
}
public BuilderExample build() {
// complicated switch statement to produce a compact properly sized immutable set omitted.
// go to https://projectlombok.org/features/Singular-snippet.html to see it.
Set<String> occupations = ...;
return new BuilderExample(name, age, occupations);
}
#java.lang.Override
public String toString() {
return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
}
}
}
We are currently attempting to implement an extension to SlingModels, to allow a slingmodel to be persisted to the JCR directly.
Our strategy has 2 considered starting conditions:
1. A new object that is to be persisted
2. An object that has been retrieved from the JCR, altered, and is then to be persisted again
For situation 1, we are using reflection to examine the object, create a new node for the model, insert properties for any of the primitive variables found, and recursively use the same persistence approach for any complex model objects found as variables, and collections.
My question on best approach relates to situation 2. If we pull out an object from the repository, we cannot be guaranteed that the node will not be synchronously changed in the meantime. Thus, we would like to implement a change watcher on the SlingModel that keeps a transaction journal on any changes made. The transactions can then be used to set the relevant properties when persisting the object back to the JCR again.
I have considered using an observer pattern, but this would mean that we would need to implement a function within the setter on each SlingModel, which is not ideal at all, as it requires a developer to remember to add the code and do it correctly.
Ideally, I would like to implement something like an interceptor directly on the variable, or if not possible, on the setter itself, and mandate that each model would then need to use a getter/setter for each variable. We can configure code scanning tools to enforce developers to implement getter/setters.
What would the be the best way to approach the change watcher here?
import java.util.List;
public class Teacher {
private String userName;
private String cource;
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getCource() {
return cource;
}
public void setCource(String cource) {
this.cource = cource;
}
}
public class Student {
private String name;
private int age;
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 class ClassFacadeCglib implements MethodInterceptor{
private Object target;
public Object getInstance(Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
// callback method
enhancer.setCallback(this);
// create proxy object
return enhancer.create();
}
#Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
if(method.getName().startsWith("set")){
System.out.println(method.getName()+" start");
proxy.invokeSuper(obj, args);
System.out.println(method.getName()+" end..");
}
if(method.getName().startsWith("get")){
System.out.println(method.getName()+" start");
proxy.invokeSuper(obj, args);
System.out.println(method.getName()+" end");
}
return null;
}
}
public class Main {
public static void main(String[] args) {
ClassFacadeCglib cglib=new ClassFacadeCglib();
Teacher teacher=(Teacher)cglib.getInstance(new Teacher());
teacher.setCource("Math");
teacher.getUserName();
}
}
Note :
cglib-full-2.0.2.jar is required for running.
see https://repo1.maven.org/maven2/cglib/cglib-full/2.0.2/
public class Person {
public String Person(String name) {
return name;
}
public static void main(String[] args) {
Person one = new Person("hendry");
}
}
What am I doing wrong?
This is not a constructor, because you have declared a return type. It's just a method that happens to have the same name as your class.
public String Person(String name) {
Without an explicit constructor, the compiler inserts an implicit default constructor with no parameters, so there is a conflict with the number of arguments.
Remove the return type; no return type should be specified on constructors, not even void:
public Person(String name)
Don't return anything from the constructor. But, you may wish to store the parameter in an instance variable, and you may wish to add a method that returns that instance variable (a "getter").
Constructors don't have a return type. Why? Because their purpose of existing is to initialize attributes.
Maybe what you are looking for is a getter method:
public String getPerson(String name) {
return name;
}
But if you want it as constructor, to initialize an attribute, first declare it, and then assign the parameter of the constructor to it:
public class Person {
private String name;
public String Person(String pName) {
this.name = pName;
}
...
}
public String Person(String) is not valid constructor as constructors dont have return type. So actually as per compiler there is no parameterized constructor in your code but you are trying to call one
Constructor returns nothing. They can take parameter but they don't return anything.
It must be like this:
private String name;
public Person(String name) {
this.name = name; }
public String getName(){
return this.name; }
public static void main(String[] args) {
Person one = new Person("hendry");
String name = one.getName();
}
Hi i have the following code:
public List<Person> findAll() {
List<Person> copy = new ArrayList<Person>();
for (Person person : personer) {
copy.add(person);
}
return copy;
}
But when i test this i only retrieve the following and not the value:
[Person#15c7850, Person#1ded0fd,
Person#16a9d42]
How do i get the values and not like above. Where i am inserting the person the code looks like this:
public boolean insert(String name, String nbr) {
if (containsName(name)) {
return false;
}
Person person = new Person(name, nbr);
personer.add(person);
return true;
}
and here is my Person class:
class Person {
private String name;
private String nbr;
public Person (String name, String nbr) {
this.name = name;
this.nbr = nbr;
}
public String getName() {
return name;
}
public String getNumber() {
return nbr;
}
}
You're already receiving the objects you want.
What you see is an internal representation of these objects.
You must iterate through them and call their respective methods to see the information you probably want to see.
If you're not satisfied with these results, you must override toString to provide you with more meaningful information.
Update:
after seeing your edit, you should add toString similar to this one in your Person class:
#Override
public String toString() {
return "Name: " + name + ", number: " + nbr;
}
By the way, you're storing nbr as a string, and it's obvious it should be an integer. So, I'd suggest changing its type to an int or Integer.
You are getting a List object back. You can use the Person object to get the data that you need. To get to the Person objects, iterate over the list.
List<Person> people = findAll();
for Person p : people {
String phoneNumber = p.phoneNumber();
String name = p.Name();
}
Override the toString() method in the Person class if you want a better description when printing the results.
Put something like this in the class Person (don't change the method name!):
public String toString() {
return name;//change this line
}
You are printing out an Object that has the default toString inherited from the Object class. This will print out the type of object it is and its location in memory (ie: Person#1ded0fd).
If you'd like it to see something else, you can override the toString method within your class:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public String toString() {
return this.name;
}
}
If your class looked like the above, this would allow you to do something like this:
Person p = new Person("John");
System.out.println(p);
> John
You can also just grab it as is and print out any information you want from it without overriding the toString method.
Person p = new Person("John");
System.out.println(p.getName());
> John
What value or class Person's property you aspect to retrieve from the ArrayList? This kind of value(Person#15c7850, etc) shows that the Person's object random id that assigned by JVM when you use
System.out.print(copy).