How to detect if only part of the properties is set? - java

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()

Related

How can I iterate through an ArrayList of the different class objects to search for a specific class?

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

Merge if properties are equal and remove

Below is my code (can be copy paste in https://www.compilejava.net/ with -ea as command line option).
I have an Object called Main. I have Main inside a List. If 2 properties (a and b) are equal to another Main object in the list, property strings should be concatenated. Furthermore, duplicates (when the 2 properties are equal) should than be removed (so the list can not contain 2 or more Mains in which both a and b are the same).
I tried it with a HashMap, hashCode, but I can not figure it out well. Note: I use OpenJDK-12 and can not use newer versions.
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class Main {
final int a;
final int b;
final List<String> strings;
Main(int a, int b, List<String> strings) {
this.a = a;
this.b = b;
this.strings = strings;
}
private static Main generateMain0() {
return new Main(0, 1, createListWithOneElement("merge me with main1"));
}
public static void main(String[] args) {
Main main0 = generateMain0();
Main main1 = new Main(0, 1, createListWithOneElement("merge me with main2"));
Main main2 = new Main(0, 2, createListWithOneElement("leave me alone"));
Main main3 = new Main(0, 2, createListWithOneElement("leave me alone also"));
List<Main> mains = new ArrayList<>();
mains.add(main0);
mains.add(main1);
mains.add(main2);
mains.add(main3);
// Do magic here to remove duplicate and concat property strings
// main1 should be removed, since property a and b were equal to main0 property a and b
assert mains.size() == 3;
Main main0Copy = generateMain0();
main0Copy.strings.add("merge me with main2");
// The first element should be main0. It should also contain
// the strings of main1 since property a and b were equal
assert mains.get(0).equals(main0Copy);
assert mains.get(1).equals(main2);
assert mains.get(2).equals(main3);
}
private static List<String> createListWithOneElement(String value) {
List<String> l = new ArrayList<>();
l.add(value);
return l;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Main main = (Main) o;
return a == main.a &&
b == main.b &&
strings.equals(main.strings);
}
#Override
public int hashCode() {
return Objects.hash(a, b, strings);
}
}
If, as you said in the comments, you can use a fully custom List, you can try the code below.
Internally, it uses a combination of a List and a Map to find out if a combination of a and b was already added to the "List". If yes, it adds all strings of the given Main to the existing Main. If not, it adds the given Main the the list.
package example;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class MainList {
private final List<Main> mains;
private final Map<Key, Main> lookup;
public MainList() {
this.mains = new ArrayList<>();
this.lookup = new HashMap<>();
}
public Main get(int index) {
return this.mains.get(index);
}
public void add(Main main) {
final Key key = new Key(main.a, main.b);
Main existingMain = this.lookup.get(key);
if (existingMain == null) {
this.mains.add(main);
this.lookup.put(key, main);
} else {
existingMain.strings.addAll(main.strings);
}
}
public void remove(Main main) {
final Key key = new Key(main.a, main.b);
Main existingMain = this.lookup.get(key);
if (existingMain != null) {
if (existingMain.equals(main)) {
this.mains.remove(existingMain);
this.lookup.remove(key);
} else {
existingMain.strings.removeAll(main.strings);
}
}
}
public void remove(int index) {
final Main removedMain = this.mains.remove(index);
final Key key = new Key(removedMain.a, removedMain.b);
this.lookup.remove(key);
}
public int size() {
return this.mains.size();
}
private static class Key {
private final int a;
private final int b;
private Key(int a, int b) {
this.a = a;
this.b = b;
}
#Override
public boolean equals(Object object) {
if (this == object) {
return true;
} else if (object == null || getClass() != object.getClass()) {
return false;
}
Key key = (Key) object;
return this.a == key.a && this.b == key.b;
}
#Override
public int hashCode() {
return 31 * this.a + 31 * this.b;
}
}
}

Java Annotation or Code Generation

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.

assert p.name("String").equals("Child String")

interface Parent {
public String name(Object b);
}
class Child implements Parent {
public String name(Object b) {
return [???];
}
public String name(String b) {
return "Child " + [???];
}
}
public class Exercise {
public static void main(String[] args) {
Parent p = new Child();
assert p.name("String").equals("Child String");
}
}
Is there any way to replace the '[???]' within the code above so that the assert returns trues?
I don't understand why the method name is overloaded. But you could use instanceof to check for the type of the parameter b.
public String name(Object b) {
if (b instanceof String) {
return name((String) b);
}
return "something else";
}
public String name(String b) {
return "Child " + b;
}

Find the number of times a specific element occurs in an Array list

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.

Categories