Give a nested class definition
class A {
B b;
public B getB() {
return b;
}
}
class B {
ArrayList<C> list;
public getListC() {
return list;
}
}
class C {
D d;
public D getD() {
return d;
}
}
class D {
E e;
public E getE() {
return e;
}
}
Now let's say that I have an Instance of Class A and I want to get access to an instance of E through A's instance like following
E someMethod(A a) {
if (a == null
|| a.getB() == null
|| a.getB().getListC() == null
|| a.getB().getList().isEmpty()
|| a.getB().getList().get(0) == null
|| a.getB().getList().get(0).getD() == null) {
return null;
}
return a.getB().getList().get(0).getD().getE();
}
Now I want to know if there is a way to automatically genererate the above code using Annotation or some other tool so that I don't have to repeaditly write such a code. I should only be doing following
E someMethod(A a) {
#AwesomeAnnotation(a.getB().getList().get(0).getD().getE());
}
KludJe is probably what you want.
Related
How can I iterate through an ArrayList of the different class objects to search for a specific class?
productionDate is an interface that is implemented in base classes.
Here is the code but it doesn't print anything :)
ArrayList<ProductionDate> storage;
public void search(Class c, int itemCount){
if(storage.getClass() == c){
for(ProductionDate d : storage){
if(d instanceof ProductionDate &&
((ProductionDate)d).getItemCount() >= itemCount){
System.out.println(d);
}
}
}
}
First, Remove the first if statement.
Secondly, You should use the class that implements ProductionDate interface in order to check whether the object belongs to that specific class. I think that class is Class c here.
So:
ArrayList<ProductionDate> storage;
public void search(Class c, int itemCount){
for(ProductionDate d : storage){
if(d instanceof c &&
((c)d).getItemCount() >= itemCount){
System.out.println(d);
}
}
}
I do not know how you call the method, but this works:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
ArrayList<Object> arrayList = new ArrayList<>();
Class c = arrayList.getClass();
search(c, 12);
}
public static void search(Class c, int itemCount) {
ArrayList<ProductionDate> storage = new ArrayList<>();
storage.add(new ProductionDate(13));
storage.add(new ProductionDate(15));
storage.add(new ProductionDate(11));
if (storage.getClass() == c) {
for (ProductionDate d : storage) {
if (d instanceof ProductionDate &&
((ProductionDate) d).getItemCount() >= itemCount) {
System.out.println(d);
}
}
}
}
private static class ProductionDate {
int itemCount;
public ProductionDate(int itemCount) {
this.itemCount = itemCount;
}
public int getItemCount() {
return itemCount;
}
}
}
output:
Main$ProductionDate#5acf9800
Main$ProductionDate#4617c264
Solution guide for TIJ4 for exercise 28 from chapter 17 says:
When a class extends a concrete Comparable class (as T3<A,B,C>
extends T2<A,B> in the original program), and adds a significant
field, there is no way to simultaneously implement compareTo()
correctly. (...) The same holds true for equals()"
I did this exercise using inheritance as it was used in "original
program" and it works as well (?). In exercise some needs to implement
equals() method and Comparable interface.
public class TwoTuple<A extends Comparable, B extends Comparable>
implements Comparable {
public final A first;
public final B second;
public TwoTuple(A a, B b) {
first = a;
second = b;
}
public String toString() {
return "(" + toString2() + ")";
}
protected String toString2() {
return first + ", " + second;
}
public boolean equals(Object o) {
return o != null &&
o.getClass() == getClass() &&
(first == null
? getClass().cast(o).first == null
: first.equals(getClass().cast(o).first)) &&
(second == null
? getClass().cast(o).second == null
: second.equals(getClass().cast(o).second));
}
public int hashCode() {
int result = 17;
if(first != null) {
result = result * 37 + first.hashCode();
}
return second == null ? result : result * 37 + second.hashCode();
}
public int compareTo(Object o) {
if(o.getClass() != getClass()) {
throw new ClassCastException();
}
int comparation = first.compareTo(getClass().cast(o).first);
return comparation != 0
? comparation
: second.compareTo(getClass().cast(o).second);
}
}
public class ThreeTuple<A extends Comparable, B extends Comparable, C extends Comparable>
extends TwoTuple<A, B> {
public final C third;
public ThreeTuple(A a, B b, C c) {
super(a, b);
third = c;
}
protected String toString2() {
return super.toString2() + ", " + third;
}
public boolean equals(Object o) {
return super.equals(o) &&
(third == null
? getClass().cast(o).third == null
: third.equals(getClass().cast(o).third));
}
#Override
public int hashCode() {
int result = super.hashCode();
return third == null ? result : result * 37 + third.hashCode();
}
#Override
public int compareTo(Object o) {
int comparation = super.compareTo(o);
return comparation != 0
? comparation
: third.compareTo(getClass().cast(o).third);
}
}
Is my solution correct or I missed something?
To make it working I needed to skip generics implementing Comparable interface, so not this way:
TwoTuple(...) implements Comparable<TwoTuple> {
(...)
int compareTo(TwoTuple o) {
but just:
TwoTuple(...) implements Comparable {
(...)
int compareTo(Object o) {
Maybe this is wrong statement which not obeying docs (?).
--
regards
Pawel
I am trying to find how many time one string occurs in an ArrayList. I managed to find by using Collections.frequency(list,object);
public class Main {
public static void main(String[] args) {
ArrayList<Main> d = new ArrayList<Main>();
Main m = new Main();
m.setA("a");
d.add(m);
Main m11 = new Main();
m11.setA("a");
d.add(m11);
Main m111 = new Main();
m111.setA("a");
d.add(m111);
int c = Collections.frequency(d, m11);
System.out.println(c);
}
private String a,b,c;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
#Override
public boolean equals(Object o) {
return a.equals(((Main)o).a);
}
}
In the above code I manage to find occurrences of a. But how can I find other stuff also, like if I want to find occurrences of b and calso? Is there a way I can do it? Can I have many equals function?
Implementation of frequency.
public static int frequency(Collection<?> c, Object o) {
int result = 0;
if (o == null) {
for (Object e : c)
if (e == null)
result++;
} else {
for (Object e : c)
if (o.equals(e))
result++;
}
return result;
}
So this works on equals method and you can't have more than one equals.
You have to manually iterate over the list and find the frequency for different properties.
ArrayList<Main> d = new ArrayList<Main>();
int counter = 0;
foreach( var item in d )
{
if( item = "The string you desire" )
{
counter += 1;
}
}
// This is the total count of the string you wanted in the collection
console.write(counter);
If you want to make this a generic function, it would just take 2 parameters, the collection, and the item you desire.
String a = "1";
String b;
...
String n = "100";
How can I check if none or all of the properties have been set?
I want to get "valid" if a..n all properties are set, and also "valid" if none if them are set. But "invalid" if only partially set.
How can this be solved? Of course I could write endless boolean statements like
(a != null && b != null & .. & n != null) || (a == null && b == null & .. & n == null)
But there must be a better way.
Having a sample class
public class SampleClass {
private String a, b, c, d, e, f;
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
public String getE() {
return e;
}
public void setE(String e) {
this.e = e;
}
public String getF() {
return f;
}
public void setF(String f) {
this.f = f;
}
}
you can get the Java Bean information using the java.beans.Introspector
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import org.junit.Test;
public class IntrospectorTest {
#Test
public void test() throws IntrospectionException, IllegalArgumentException,
IllegalAccessException, InvocationTargetException {
SampleClass sampleClass = new SampleClass();
sampleClass.setA("value for a");
sampleClass.setB("value for b");
sampleClass.setC("value for c");
sampleClass.setD("value for d");
sampleClass.setE("value for e");
sampleClass.setF("value for f");
int withValue = 0;
PropertyDescriptor[] descriptors = Introspector.getBeanInfo(SampleClass.class, Object.class).getPropertyDescriptors();
for (PropertyDescriptor propertyDescriptor : descriptors) {
Object value = new PropertyDescriptor(propertyDescriptor.getName(), SampleClass.class).getReadMethod().invoke(sampleClass);
if (value!=null) {
withValue++;
System.out.println(propertyDescriptor.getName() + ": " + value);
}
}
if (descriptors.length == withValue || withValue == 0) {
System.out.println("valid");
}else{
System.err.println("Invalid!!");
}
}
}
and voila!
Pay atention at this line
Introspector.getBeanInfo(SampleClass.class, Object.class).getPropertyDescriptors();
if you call the getBeanInfo method with your class as one and only parameter the Introspector will return all the Property Descriptors in the class hierarchy, so you can call the method with an optional stop class where the Introspector stops reading the Property Descriptors.
Hope this helps.
You can use map then iterate over it to check if any of the value is null and set status accordingly.
You can also try with this: Collections.frequency(map.values(), null) == map.size()
I have two objects of same type.
Class A {
String a;
List b;
int c;
}
A obj1 = new A();
A obj2 = new A();
obj1 => {a = "hello"; b = null; c = 10}
obj2 => {a = null; b = new ArrayList(); c = default value}
Can you please let me know what is the best way to combine this objects into single object?
obj3 = {a = "hello"; b = (same arraylist from obj2); c = 10}
This works as long as you have POJOs with their own getters and setters. The method updates obj with non-null values from update. It calls setParameter() on obj with the return value of getParameter() on update:
public void merge(Object obj, Object update){
if(!obj.getClass().isAssignableFrom(update.getClass())){
return;
}
Method[] methods = obj.getClass().getMethods();
for(Method fromMethod: methods){
if(fromMethod.getDeclaringClass().equals(obj.getClass())
&& fromMethod.getName().startsWith("get")){
String fromName = fromMethod.getName();
String toName = fromName.replace("get", "set");
try {
Method toMetod = obj.getClass().getMethod(toName, fromMethod.getReturnType());
Object value = fromMethod.invoke(update, (Object[])null);
if(value != null){
toMetod.invoke(obj, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
I am using Spring Framework. I was facing the same issue on a project.
To solve it i used the class BeanUtils and the above method,
public static void copyProperties(Object source, Object target)
This is an example,
public class Model1 {
private String propertyA;
private String propertyB;
public Model1() {
this.propertyA = "";
this.propertyB = "";
}
public String getPropertyA() {
return this.propertyA;
}
public void setPropertyA(String propertyA) {
this.propertyA = propertyA;
}
public String getPropertyB() {
return this.propertyB;
}
public void setPropertyB(String propertyB) {
this.propertyB = propertyB;
}
}
public class Model2 {
private String propertyA;
public Model2() {
this.propertyA = "";
}
public String getPropertyA() {
return this.propertyA;
}
public void setPropertyA(String propertyA) {
this.propertyA = propertyA;
}
}
public class JustATest {
public void makeATest() {
// Initalize one model per class.
Model1 model1 = new Model1();
model1.setPropertyA("1a");
model1.setPropertyB("1b");
Model2 model2 = new Model2();
model2.setPropertyA("2a");
// Merge properties using BeanUtils class.
BeanUtils.copyProperties(model2, model1);
// The output.
System.out.println("Model1.propertyA:" + model1.getPropertyA(); //=> 2a
System.out.println("Model1.propertyB:" + model1.getPropertyB(); //=> 1b
}
}
Maybe something like
class A {
String a;
List<..> b;
int c;
public void merge(A other) {
this.a = other.a == null ? this.a : other.a;
this.b.addAll(other.b);
this.c = other.c == 0 ? this.c : other.c;
}
}
A a1 = new A();
A a2 = new A();
a1.a = "a prop";
a2.c = 34;
a1.merge(a2);
A.merge might return a new A object instead of modifing current.
Just accommodating boolean sync. and case sensitive(camel notation)
public boolean merge(Object obj){
if(this.equals(obj)){
return false;
}
if(!obj.getClass().isAssignableFrom(this.getClass())){
return false;
}
Method[] methods = obj.getClass().getMethods();
for(Method fromMethod: methods){
if(fromMethod.getDeclaringClass().equals(obj.getClass())
&& (fromMethod.getName().matches("^get[A-Z].*$")||fromMethod.getName().matches("^is[A-Z].*$"))){
String fromName = fromMethod.getName();
String toName ;
if(fromName.matches("^get[A-Z].*")){
toName = fromName.replace("get", "set");
}else{
toName = fromName.replace("is", "set");
}
try {
Method toMetod = obj.getClass().getMethod(toName, fromMethod.getReturnType());
Object value = fromMethod.invoke(this, (Object[])null);
if(value != null){
toMetod.invoke(obj, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
return true;
}
If you create getters and setters for the attributes, you can use the copyProperties method from Commons BeanUtils.
Add this method to your POJO, then use it like myObject.merge(newObject). It uses generics to loop through your POJO's fields, so you don't mention any field names:
/**
* Fill current object fields with new object values, ignoring new NULLs. Old values are overwritten.
*
* #param newObject Same type object with new values.
*/
public void merge(Object newObject) {
assert this.getClass().getName().equals(newObject.getClass().getName());
for (Field field : this.getClass().getDeclaredFields()) {
for (Field newField : newObject.getClass().getDeclaredFields()) {
if (field.getName().equals(newField.getName())) {
try {
field.set(
this,
newField.get(newObject) == null
? field.get(this)
: newField.get(newObject));
} catch (IllegalAccessException ignore) {
// Field update exception on final modifier and other cases.
}
}
}
}
}
There is a dynamic solution to merge any two objects which require Reflection and Recursion.
public <T> T merge(T local, T remote, ArrayList<String> listOfClass)
throws IllegalAccessException, InstantiationException {
Class<?> clazz = local.getClass();
Object merged = clazz.newInstance();
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
Object localValue = field.get(local);
Object remoteValue = field.get(remote);
if (localValue != null) {
if (listOfClass.contains(localValue.getClass().getSimpleName())) {
field.set(merged, this.merge(localValue, remoteValue, listOfClass));
} else {
field.set(merged, (remoteValue != null) ? remoteValue : localValue);
}
} else if (remoteValue != null) {
field.set(merged, remoteValue);
}
}
return (T) merged;
}
Variable Description:
local: The object on to which the other will be merged
remote: The object which will be merged to the local object
listOfClass: The ArrayList of custom classes in the given object
The function returns a merged object which is good to go.
Kudos! :)
In your very special case it looks like you want a new object that takes the real values from both instances. Here is an implementation that will do that. The method should be add to class A so that it can access the fields.
public A specialMergeWith(A other) {
A result = new A();
result.a = (a == null ? other.a : a);
result.b = (b == null ? other.b : b);
result.c = (c == DEFAULT_VALUE ? other.c : c);
return result;
}
public static Object mergeObjects(Object source, Object target) throws Exception {
Field[] allFields = source.getClass().getDeclaredFields();
for (Field field : allFields) {
if(Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())){
continue;
}
if (!field.isAccessible() && Modifier.isPrivate(field.getModifiers()))
field.setAccessible(true);
if (field.get(source) != null) {
field.set(target, field.get(source));
}
}
return target;
}
Using java reflection, support only for the same class.