Java Reflection - Copy nested objects values - java

I have an object, that might have other objects or list of objects. Is there a way to iterate through these objects to copy their values into a new object? What I want to do is merge 2 objects to update a document in my DB, so I don't want the null values.
So far I've reached the way to do a shallow copy with no nulls value for any object with this:
public Object merge(Object target) {
try {
Field[] fields = this.getClass().getDeclaredFields();
for (Field f: fields) {
if (f.get(this) != null) {
f.set(target, f.get(this));
System.out.println(f.get(this));
}
}
} catch (IllegalAccessException e) {
return target;
}
return target;
}
Problem Statement: But now, how can I handle nested objects? Like a List of Car objects for example?

Related

java.lang.InstantiationError when creating instance of static inner class with Objenesis

I am trying to create a utility method that should be able to deep-clone any object.
(Object.clone() only works on Object implementing Cloneable and I heard it's flawed anyways.)
I am using Objenesis to create new instances of objects without the use of constructors.
However, when trying to clone a JFrame I get the following Exception:
(using this class because I think it should be a good and complex test)
java.lang.InstantiationError: [Ljava.util.concurrent.ConcurrentHashMap$Node;
at sun.reflect.GeneratedSerializationConstructorAccessor12.newInstance(Unknown Source)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.objenesis.instantiator.sun.SunReflectionFactoryInstantiator.newInstance(SunReflectionFactoryInstantiator.java:48)
at org.objenesis.ObjenesisBase.newInstance(ObjenesisBase.java:73)
I am open to any solution, not necessarily limited to Objenesis.
My Code:
private static ObjenesisStd OBJENESIS = new ObjenesisStd();
#SuppressWarnings("unchecked")
public static <T> T clone(T object, boolean deep){
if(object == null){
return null;
}else{
try {
T clone = (T) OBJENESIS.newInstance(object.getClass());
List<Field> fields = ReflectionUtil.getAllFieldsInHierarchy(object.getClass());
for(Field field : fields){
boolean isAccessible = field.isAccessible();
boolean isFinal = ReflectionUtil.isFinal(field);
field.setAccessible(true);
ReflectionUtil.setFinal(field, false);
Class<?> type = field.getType();
if(!deep || type.isPrimitive() || type == String.class){
field.set(clone, field.get(object));
}else{
field.set(clone, clone(field.get(object), true));
}
field.setAccessible(isAccessible);
ReflectionUtil.setFinal(field, isFinal);
}
return clone;
} catch (Throwable e) {
e.printStackTrace();
//throw new RuntimeException("Failed to clone object of type " + object.getClass(), e);
return null;
}
}
}
public static void main(String[] args) {
GetterSetterAccess access = new GetterSetterAccess(JFrame.class);
JFrame frame = new JFrame("Test Frame");
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
System.out.println("----------------------------------------------");
frame = clone(frame, true);
for(String attr : access.getAttributes()){
System.out.println(attr + " " + access.getValue(frame, attr));
}
}
EDIT: Got it to work with the accepted answer and a few more fixes:
Avoided cloning Wrappers of Primitive Types (Integer.class etc.)
Avoided cloning Classes (Objects of the class Class.class)
Stored the cloned objects in a Map and reused them, so if Object A has a reference to Object B and Object B one to Object A it doesn't get stuck in an infinite loop. I also used a Map that checks for exact equality (==) instead of using equals().
Created a custom exception class which would just be passed on instead of throwing a new exception on every level (causing a huge caused-by-depth).
I finally figured it out. Your code doesn't handle arrays. So it fails with instantiating "[Ljava.util.concurrent.ConcurrentHashMap$Node;" which is an array of Nodes.
However, I will advocate that indeed, you should not do that. You will end up with fairly complicated code. Depending on what you want to do, you could use Jackson or XStream to do a marshall / unmarshall to perform the copy.
If you really want to continue that path, you will need something like this after the null check of your clone method.
if(object.getClass().isArray()) {
int length = Array.getLength(object);
Object array = Array.newInstance(object.getClass().getComponentType(), length);
for (int i = 0; i < length; i++) {
Array.set(array, i, clone(Array.get(object, i), true));
}
return (T) array;
}

How to Return values for each iteration?i'm able to send only last iteration values to my db

I'm using deserialize method which return values at last.I'm using for loop. first loop for getting each object and applying my stuff to each single object in second for loop.
My problem:
if I'm having 5 objects in the first loop all the 5 objects return values should be inserted in the database at the end of my program but only last (5th) object values are inserted into my database.ie.,only 5th object values are return at the end.(i declared all my obj in class not in the loop)
How can i store all 5 objects return values into my database.
How can I send each return values to db for each iteration.
public class MainParserSpout implements Scheme{
public List<Object> deserialize(byte[] arg0) {
try{
for(;;){
//loop of objects
for(;;){
//mystuff for each object
}
}
}catch(Exception e){}
return new Values();
}
public Fields getOutputFields() {
return new Fields();
// TODO Auto-generated method stub
}
}
I think you are looking for something like this; add each Object to the list and then return the list:
public List<Values> deserialize (byte[] arg0) {
List<Values> list = new ArrayList<>();
for (some condition ...) { //while the byte array still has data or something
Values v = new Values()
//do soething with the Values object.
list.add(v);
}
return list; //return the list with all the Values Objects.
}
If you want some more specific recommendation, you should make it clearer what you are trying to do, but this is probably the general idea you are looking for.

Find a specific entry in an ArrayList based upon another ArrayList?

I have a product class
public class Produs {
private String denumire;
private String categorie;
private String taraOrigine;
private double pret;
}
with different constructors to fit my needs. I have an ArrayList of this type where all the Products have all the fields ( the list is generated by parsing a file ) . And another list in which there are products with only the name and country of origin filled ( rest of the fields are null ).This list is also generated from another list.
My question is , how can I search the first list, using the known fields of a product located in the second list , so that I can complete every object in the first list ?
I have tried with
public Produs getProdus(Produs p)
{
for(Produs prod:produse)
{
if ((prod.getDenumire().equals(p.getDenumire()) && (prod.getTaraOrigine().equals(p.getTaraOrigine()))));
{
return prod;
}
}
return null;
}
where produse is my list of products where all fields have values and p is a Product constructed using only 2 fields.
I have also tried with overwriting equals and hashcode. The problem is that when it finds the element , the loop stops.
You need to populate it before returning the actual object.
public Produs getProdus(Produs p)
{
for(Produs prod:produse)
{
if ((prod.getDenumire().equals(p.getDenumire()) && (prod.getTaraOrigine().equals(p.getTaraOrigine()))));
{
if (prod.getCategorie() == null) {
prod.setCategorie(p.getCategorie());//assuming you have getter and setter already in Produs
}
return prod;//remove this statement, if you want multiple products to be updated and make this method as void type instead of returning Produs type. Remove return null as well from end of this method.
}
}
return null;
}
If you want to list all the producs whose criteria matches then you could create a list and populate that like below:
public void getProdus(Produs p)
{
List<Produs> productList = new ArrayList<Produs>();
for(Produs prod:produse)
{
if ((prod.getDenumire().equals(p.getDenumire()) && (prod.getTaraOrigine().equals(p.getTaraOrigine()))));
{
productList.add(prod);
}
}
for(Produs prod:productList) {//iterate over the list who matched the criteria and amend it with properties from p.
}
}
Your getProdus() function is correct. You need to call it in a loop for every object in the first list.

Java - looping and through variables of instance of a class

I have a class
Class Test{
private String something ;
private String somethingElse;
private String somethingMore;
}
I am creating an instance of this.
myInst = new Test();
and adding values to first and second variables.
Now I need to check if any of the variable is null.
I know I can do this like if(myInst.something == null)
but for each item I add to the class it's difficult to do.
Is there anyway that i can check the instance by looping through all elements and seeing anything is null.
just like -
for(i=0; i< myInstanceVariables ; i++)
{
if(myInstanceVariable == null ){
//do something
donotDisplay(myInstanceVariable)
}
TIA
You can use Reflection using Fields from your instance. In your class, add this code. It will take all the fields and get their value.
Field[] fields = getClass().getDeclaredFields(); // get all the fields from your class.
for (Field f : fields) { // iterate over each field...
try {
if (f.get(this) == null) { // evaluate field value.
// Field is null
}
} catch (IllegalArgumentException ex) {
ex.printStackTrace();
} catch (IllegalAccessException ex) {
ex.printStackTrace();
}
}
Here is a sample code: https://ideone.com/58jSia
You have to use reflection over Field of the Class.
myInst = new Test();
for (Field field : myInst.getClass().getDeclaredFields())
if (field.get(myInst) == null)
// do something
You can use reflection, however, in your case you only have String values, and thus it would also make sense to use a HashMap (for instance):
HashMap hm = new HashMap();
hm.put("something", "itsValue");
hm.put("somethingElse", null);
Now you can put as many values as you would like, and iterate through them like this:
Set set = hm.entrySet();
Iterator i = set.iterator();
while(i.hasNext()){
Map.Entry me = (Map.Entry)i.next();
System.out.println(me.getKey() + " : " + me.getValue() );
}

Display Hibernate Query in JTable

I'm seeking an efficient way to display an SQL table queried via Hibernate in a JTable.
Query q = em.createNamedQuery("Files.findAll");
List rl = q.getResultList();
It would probably be preferable to use the List returned by that (In this case, that would make a list of Files objects (where Files is an internal class, not java.io.File)), but I won't be picky as long as it is neat.
I have one answer I worked up below, but that doesn't work very well. I'd going to end up having to write a TableModel for it if I keep going down this path.
There are a lots and lots of ways to do this, but are you looking for something that would automatically figure out the columns or what? If you used the java reflection pieces you can read the Hibernate annotations to find out the column names and populate the JTable that way...
Otherwise this is just a straight forward piece of code that a. creates a JTable and TableModel, and b. populates the display with the database data.
EDIT:
I think this example may cover walking the annotation tree and processing them. The specifics are the AnnotationProcessorFactory part iirc.
EDIT 2:
I also found this library which is built to help lookup annotations at runtime. One of their examples is looking up Entity classes in hibernate to build a resource list - I believe you could do something similar to find classes that that implement #column, or #basic etc. This should allow you via reflection to pretty easily do it, but as I said java's standard library already provides the ability to walk the annotation tree to find out the column names - at which point creating the JTable from that should be very easy to do in a programmatic way.
EDIT 3:
This code is all that and a bag of chips! From here you should easily be able to walk the list of maps and pull out all of the info you want, the value, its class type, the field name for the column headers... Note that it isn't particularly safe.. I've dropped out all of the error code I did while testing to keep it short...
List<Map> createTable(List queryResults) {
List<Map> r = new LinkedList<Map>();
for (Object o : queryResults) {
r.add(entityMap(o));
}
return r;
}
Map entityMap(Object obj) throws Throwable {
Map m = new HashMap();
for (Field field : getFields(obj.getClass())) {
Method method = getMethod(field);
Object value = method.invoke(obj);
m.put(field, value);
}
return m;
}
List<Field> getFields(Class<?> clazz) {
List<Field> fields = new LinkedList<Field>();
for (Field field : clazz.getDeclaredFields()) {
Column col = field.getAnnotation(Column.class);
if (col != null)
fields.add(field);
}
return fields;
}
Method getMethod(Field field) throws NoSuchMethodException {
Class<?> clazz = field.getDeclaringClass();
String name = "get" + uppercase(field.getName());
Method method = clazz.getMethod(name);
return method;
}
String uppercase(String str) {
return str.substring(0,1).toUpperCase() + str.substring(1);
}
Did you take a look at the org.hibernate.metadata classes. These provide you metadata information about classes and collections. You can also make calls to SessionFactory.getClassMetadata(Class) to get the metadata information for the class in question.
In the answer below I expect that your HQL returns not a list of objects, but a list of arrays of necessary properties that you wish to show in JTable (i.e. that you're using so calling report queries).
In that case you can write simple TableModelAdapter that will be used as a TableModel for JTable.
public class TableModelAdapter extends AbstractTableModel{
private List<Object[]> list;
public TableModelAdapter(List<Object[]> aList){
list = aList;
}
public int getColumnCount() {
if (list == null){
return 0;
}
if (list.size() == 0){
return 0;
}
return list.get(0).length;
}
public int getRowCount() {
if (list == null){
return 0;
}
return list.size();
}
public Object getValueAt(int row, int column) {
if (list == null){
return null;
}
return list.get(row)[column];
}
}
If you have to return list of objects we can change the example and path throw properties via reflection instead of array.
Well, here's what I ended up doing for now:
//client-side class
public String[][] getFilesArray() {
List<Files> files = remote.getFiles();
String[][] x = new String[files.size()][];
for (int i = 0; i < files.size(); i++) {
x[i] = files.get(i).getStringArray();
}
return x;
}
//DAO class
public String[] getStringArray() {
return new String[] {
fileid.toString(),
name,
DateFormat.getInstance().format(timestamp),
status,
hash
};
}
public static String[] getColumnNames() {
return new String[] {
"Id",
"Name",
"Timestamp",
"Status",
"Hash"
};
}
JIDE Data Grids provides a HibernateTableModel that could provide the functionality you are looking for if you are happy to buy a third party library.
private void DataRetrive() {
DefaultTableModel tbl = (DefaultTableModel) jtblDataRet.getModel();
tbl.setRowCount(0);
try {
// call local method which was opensession
opensession();
if (!session.isOpen()) {
session = Hibernate_ut.getSession().openSession();
tx = session.beginTransaction();
String hQ = "From Student";
Query que = session.createQuery(hQ, Student.class);
List<Student> list = (List) que.list();
for (int i = 0; i < list.size(); i++) {
Vector vt = new Vector();
vt.add(0, list.get(i).getStudentName().toString());
vt.add(1, list.get(i).getStudentAddr().toString());
vt.add(2, list.get(i).getGrade().toString());
vt.add(3, list.get(i).getContact().toString());
tbl.addRow(vt);
}
}
} catch (HibernateException e) {
System.out.println(e);
e.printStackTrace();
tx.rollback();
}
}

Categories

Resources