Finding Difference of 2 sets in Java - java

I have two hashsets in Java, of which I want to find the difference
I tried the following code as recommended by Oracle's doc
HashSet<RunningTaskInfo> difference = new HashSet<ActivityManager.RunningTaskInfo>(newRunningTasks);
HashSet<RunningTaskInfo> oldRunningTaskInfos = new HashSet<ActivityManager.RunningTaskInfo>(oldRunningTasks);
difference.removeAll(oldRunningTaskInfos);
for(RunningTaskInfo d : difference){
ComponentName cn = d.baseActivity;
Log.d("com.manugupt1.fua","Comparing : " + i + cn.getPackageName() + "****" + cn.getClassName() + "****" + cn.getShortClassName());
}
Only those data values that are not in oldRunningTasks should be shown but I get only the elements from oldRunningTasks. Any suggestions

EDIT: Adding Matt's comments
RemoveAll is comparing objects pointers instead of the content, and that's why it's not able to find any coincidences.
You can check this by watching the return value of
difference.removeAll(oldRunningTaskInfos);
(false means "no coincidences")
Probably the best approach would be encapsulating RunningTask into an object that overrides equals() and hashcode() methods, and then invoke removeAll. Consider the following sample code that do the same but using List's:
// Getting two snapshots
ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> oldRunningTasks=am.getRunningTasks (100);
List<ActivityManager.RunningTaskInfo> newRunningTasks=am.getRunningTasks (100);
// We add a new fake task to test that removeAll() is working
ActivityManager.RunningTaskInfo fakeTask=new ActivityManager.RunningTaskInfo ();
fakeTask.baseActivity=new ComponentName("Fake","Fake");
fakeTask.id=1234;
newRunningTasks.add(fakeTask);
// Converting to lists of Comparable objects and get the differences.
List<RunningTaskInfoComparable> list_difference = convertToComparable(newRunningTasks);
List<RunningTaskInfoComparable> list_oldRunningTaskInfos = convertToComparable(oldRunningTasks);
boolean res=list_difference.removeAll(list_oldRunningTaskInfos);
for(RunningTaskInfoComparable d : list_difference){
ComponentName cn = d.getBaseActivity();
Log.d("com.test.tasks","Comparing List: " + cn.getPackageName() + "****" + cn.getClassName() + "****" + cn.getShortClassName());
}
where RunningTaskInfoComparable is implemented like this:
public class RunningTaskInfoComparable {
android.app.ActivityManager.RunningTaskInfo runningTaskObject;
public RunningTaskInfoComparable (android.app.ActivityManager.RunningTaskInfo obj)
{
runningTaskObject=obj;
}
// Observer
public ComponentName getBaseActivity(){
return runningTaskObject.baseActivity;
}
#Override
public int hashcode()
{
int result = HashCodeUtil.SEED;
// More data could be added to the hash...
result = HashCodeUtil.hash( result, runningTaskObject.id);
return result;
}
#Override
public boolean equals(Object obj) {
if (!(obj instanceof RunningTaskInfoComparable)) {
return false;
}
// Criteria: Same task id means same entity
return (runningTaskObject.id==((RunningTaskInfoComparable)obj).runningTaskObject.id);
}
}
and convertToComparable looks like:
private List<RunningTaskInfoComparable> convertToComparable (List<ActivityManager.RunningTaskInfo> _original)
{
List<RunningTaskInfoComparable> retList=new ArrayList<RunningTaskInfoComparable>();
for(RunningTaskInfo t : _original){
RunningTaskInfoComparable tc = new RunningTaskInfoComparable(t);
retList.add(tc);
}
return retList;
}

Related

Generics and type erasure in Java issue

I currently face the following issue:
I am trying to refactor a recursive algorithm to an iterative one. What this recursive algorithm does is this:
method1 is passed some initial parameters. Based on a processing that takes place at the beginning of method1, method2 is invoked with these parameters. Now method2 uses some conditions and based on the one that is satisfied method1 is invoked again with the appropriate parameters.
Now, based on the answer on the link I've provided above I did the same thing. But I have to pass parameters around so I did this:
Stack<ArrayList<Object>> stack (the stack for the ArrayList<Object> objects)
ArrayList<Object> parametersForSync = new ArrayList<Object>();
ArrayList<Object> paramForHandle = new ArrayList<Object>();
(Each array list of objects is a list of the parameters to be passed to both the methods. The first array list is for the first method and the second for the second method.)
Assuming I pop and push array lists down the stack correctly I face the following issue which is my main problem and the reason of this question:
Within method2 I have to check whether the object (that was on the array list and is passed to the method) is an instanceof another class of mine. Now I have some conditions there which do not get satisfied when in fact they should.
Is this because of java's type erasure?
Is there anyway to overcome this?
If am not clear at a certain point in my explanations please ask me to clarify.
Edit:
What follows is the code that replaces the recursion that goes like this:
syncWithServer(parameter set x){
handleResultArray(parameter set y);
};
handleResultArray(parameter set ){
syncWithServer(parameter set w)
}
===========================================================
Stack<ArrayList<Object>> stack = new Stack<ArrayList<Object>>();
ArrayList<Object> paramList = new ArrayList<Object>();
paramList.add(oeHelper);
paramList.add(false);
paramList.add(domain);
paramList.add(null);
paramList.add(true);
paramList.add(10000);
paramList.add(true);
stack.push(paramList);
int counter = 0;
ArrayList<Object> parametersForSync = new ArrayList<Object>();
ArrayList<Object> paramForHandle = new ArrayList<Object>();
while (!stack.isEmpty()) {
Log.d(TAG, "Loop: " + counter);
parametersForSync = stack.pop();
paramForHandle = ((OEHelper) parametersForSync.get(0))
.syncWithServer(
// why error here?
(boolean) parametersForSync.get(1),
(OEDomain) parametersForSync.get(2),
(List<Object>) parametersForSync.get(3),
(boolean) parametersForSync.get(4),
(int) parametersForSync.get(5),
(boolean) parametersForSync.get(6));
parametersForSync = ((OEHelper) paramForHandle.get(3))
.handleResultArray(
(OEFieldsHelper) paramForHandle.get(0),
(JSONArray) paramForHandle.get(1),
(boolean) paramForHandle.get(2));
if (parametersForSync.size() != 0) {
stack.push(parametersForSync);
}
counter++;
Now the first method:
public ArrayList<Object> syncWithServer(boolean twoWay, OEDomain domain,
List<Object> ids, boolean limitedData, int limits,
boolean removeLocalIfNotExists) {
Log.d(TAG, "syncWithServer");
List<OEColumn> dbCols = mDatabase.getDatabaseColumns();
List<OEColumn> dbFinalList = new ArrayList<OEColumn>();
ArrayList<Object> parametersList = new ArrayList<Object>();
Log.d(TAG, "Columns & finalList created");
for (OEColumn col : dbCols) {
if (!mOne2ManyCols.contains(col.getName())) {
dbFinalList.add(col);
}
}
OEFieldsHelper fields = new OEFieldsHelper(dbFinalList);
try {
if (domain == null) {
domain = new OEDomain();
}
if (ids != null) {
domain.add("id", "in", ids);
}
if (limitedData) {
mPref = new PreferenceManager(mContext);
int data_limit = mPref.getInt("sync_data_limit", 60);
domain.add("create_date", ">=",
OEDate.getDateBefore(data_limit));
}
if (limits == -1) {
limits = 50;
}
Log.d(TAG, "*****.search_read() started");
JSONObject result = *****.search_read(mDatabase.getModelName(),
fields.get(), domain.get(), 0, limits, null, null);
Log.d(TAG, "***.search_read() returned");
mAffectedRows = result.getJSONArray("records").length();
parametersList.add(fields);
parametersList.add(result.getJSONArray("records"));
parametersList.add(removeLocalIfNotExists);
parametersList.add(OEHelper.this);
//This parametersList contains the parameters that must be used to invoke the next method
Now the second method:
=================================================
public ArrayList<Object> handleResultArray(
OEFieldsHelper fields, JSONArray results,
boolean removeLocalIfNotExists) {
Log.d(TAG, "handleResultArray");
ArrayList<Object> parametersList = new ArrayList<Object>();
// ArrayList<Object> parameterStack = new ArrayList<Object>();
try {
fields.addAll(results);
List<OERelationData> rel_models = fields.getRelationData();
Log.d(TAG, "rel_models: "+rel_models.size());
for (OERelationData rel : rel_models) {
// Handling many2many records
if (rel.getDb().getClass()==OEManyToMany.class
/*instanceof OEManyToMany*/) {//TODO type erasure?
Log.v(TAG, "Syncing ManyToMany Records");
OEManyToMany m2mObj = (OEManyToMany) rel.getDb();
OEHelper oe = ((OEDatabase) m2mObj.getDBHelper())
.getOEInstance();
parametersList.add(oe);
parametersList.add(false);
parametersList.add(null);
parametersList.add(rel.getIds());
parametersList.add(false);
parametersList.add(0);
parametersList.add(false);
return parametersList;
} else if (rel.getDb().getClass()==OEManyToOne.class
/*instanceof OEManyToOne*/) {
// Handling many2One records
Log.v(TAG, "Syncing ManyToOne Records");
// M2OCounter++;
OEManyToOne m2oObj = (OEManyToOne) rel.getDb();
OEHelper oe = ((OEDatabase) m2oObj.getDBHelper())
.getOEInstance();
parametersList.add(oe);
parametersList.add(false);
parametersList.add(null);
parametersList.add(rel.getIds());
parametersList.add(false);
parametersList.add(0);
parametersList.add(false);
// parametersMap.put(Counter, parametersList);
// parameterStack.add(parametersList);
return parametersList;
} else if (rel.getDb().getClass()==OEOneToMany.class
/*instanceof OEOneToMany*/) {
Log.v(TAG, "Syncing OneToMany Records");
// O2MCounter++;
OEOneToMany o2mObj = (OEOneToMany) rel.getDb();
OEHelper oe = ((OEDatabase) o2mObj.getDBHelper())
.getOEInstance();
oe.setOne2ManyCol(o2mObj.getColumnName());
parametersList.add(oe);
parametersList.add(false);
parametersList.add(null);
parametersList.add(rel.getIds());
parametersList.add(false);
parametersList.add(0);
parametersList.add(false);
// parametersMap.put(Counter, parametersList);
// parameterStack.add(parametersList);
return parametersList;
} else {
Log.v(TAG, "Syncing records with no relations"
+ rel.getDb().getClass().getSimpleName());
OEHelper oe = ((OEDatabase) rel.getDb()).getOEInstance();
parametersList.add(oe);
parametersList.add(false);
parametersList.add(null);
parametersList.add(rel.getIds());
parametersList.add(false);
parametersList.add(0);
parametersList.add(false);
return parametersList;//TODO when nothing matches this returns
}
}
List<Long> result_ids = mDatabase.createORReplace(
fields.getValues(), removeLocalIfNotExists);
mResultIds.addAll(result_ids);
mRemovedRecordss.addAll(mDatabase.getRemovedRecords());
} catch (Exception e) {
e.printStackTrace();
}
return parametersList;
}
The second method is supposed to return from within one of the conditions but none of the conditions is met
No - it is not a type erasure problem. As Oracle says:
Type erasure ensures that no new classes are created for parameterized
types; consequently, generics incur no runtime overhead.
So at runtime your classes are just plain classes and your objects are what they are, but it is not going to remove the base type information.
Why not put a log statement in and print out the class of the object?

java recursion: object is replaced rather than adding a new one

I am trying to add an object inside an object using recursion. My object contains an arrayList and I am trying to add my objects to this arrayList. But instead of adding a new object, my objects are being replaced.
My code which is doing this: This is where the logic of adding an object is being done. But it is being replaced instead.
private ArrayList<SubChapters> recursiveSubChapters(ReportingTree tree, LinkedHashMap<String, HashMap<String, String>> linkedHashMap, Boolean isSubTree){
SubChapters subChapters = new Subchapters();
ArrayList<SubChapters> alchildUnits = new ArrayList<SubChapters>();
final String chapterId = linkedHashMap.get(tree.getUnitID()).get("unit_num");
final String chapterName= linkedHashMap.get(tree.getUnitID()).get("unit_name");
if (!isSubTree) {
subChapters.set(chapterId);
subChapters.setTreeName(chapterName);
}
final ArrayList<ReportingTree> branches = tree.getBranches();
if (branches != null) {
subChapters.hasSubUnits(true);
for (ReportingTree subTree: branches) {
subChapters.setSubChapters(recursiveSubChapters(subTree, linkedHashMap, false));
//This is where the logic of adding an object is being done. But it is being replaced instead.
}
alchildUnits.add(subChapters);
}
return alchildUnits;
}
My guess is that I am messing somewhere in the loop here but I am not able to figure out where I am messing up. Thanks in advance for any suggestions or help.
My subChapters class:
public String subChapterID;
public String subChapterName;
public boolean isSubTree= false;
public ArrayList<SubChapters> subChapters;
and getters and setters.
I have coded the same solution to return a string and see the order on a jsp. It works just fine. I am not able to apply the same to my issue here.
private String recursive(ReportingTree tree, LinkedHashMap<String, HashMap<String, String>> listUnitInfo, boolean isTop) {
final String unitID = tree.getUnitID();
final HashMap<String, String> unit = listUnitInfo.get(unitID);
String output = "";
if (!isTop) {
output += "<li>" + unit.get("unit_num") + "/" + unit.get("unit_name") + "";
}
final ArrayList<ReportingTree> branches = tree.getBranches();
if (branches != null) {
if (isTop) {
output += "<li>" + unit.get("unit_num") + "/" + unit.get("unit_name") + "";
}
output += "<ul>\n";
for (ReportingTree subTree : branches) {
output += recursive(subTree, listUnitInfo, false);
}
output += "</ul>";
} else {
if (isTop) {
output += "<li>No units match your criteria.";
}
}
output += "</li>\n";
return output;
}
What you're doing is subChapters.setSubChapters, what I think you're trying to do is
subChapters.addSubChapters.
The reason why it works with the strings is because you're using += to add
the new string to the old string. Doing setSubChapters would be the same as using = with the strings.
addSubChapters would be a method that should add something to an ArrayList variable inside your subChapters class.

Hibernate query restrictions using URL key/value style parameters

I'm using Tapestry5 and Hibernate. I'm trying to build a criteria query that uses dynamic restrictions generated from the URL. My URL context is designed like a key/value pair.
Example
www.mywebsite.com/make/ford/model/focus/year/2009
I decode the parameters as followed
private Map<String, String> queryParameters;
private List<Vehicle> vehicles;
void onActivate(EventContext context) {
//Count is 6 - make/ford/model/focus/year/2009
int count = context.getCount();
if (count > 0) {
int i;
for (i = 0; (i + 1) < count; i += 2) {
String name = context.get(String.class, i);
String value = context.get(String.class, i + 1);
example "make"
System.out.println("name " + name);
example "ford"
System.out.println("value " + value);
this.queryParameters.put(name, value);
}
}
this.vehicles = this.session.createCriteria(Vehicle.class)
...add dynamic restrictions.
}
I was hoping someone could help me to figure out how to dynamically add the list of restrictions to my query. I'm sure this has been done, so if anybody knows of a post, that would be helpful too. Thanks
Exactly as the other answer said, but here more spelt out. I think the crux of your question is really 'show me how to add a restriction'. That is my interpretation anyhow.
You need to decode each restriction into its own field.
You need to know the Java entity property name for each field.
Then build a Map of these 2 things, the key is the known static Java entity property name and the value is the URL decoded data (possibly with type conversion).
private Map<String, Object> queryParameters;
private List<Vehicle> vehicles;
void onActivate(EventContext context) {
//Count is 6 - make/ford/model/focus/year/2009
int count = context.getCount();
queryParameters = new HashMap<String,Object>();
if (count > 0) {
int i;
for (i = 0; (i + 1) < count; i += 2) {
String name = context.get(String.class, i);
String value = context.get(String.class, i + 1);
Object sqlValue = value;
if("foobar".equals(name)) {
// sometime you don't want a String type for SQL compasition
// so convert it
sqlValue = UtilityClass.doTypeConversionForFoobar(value);
} else if("search".equals(name) ||
"model".equals(name) ||
"year".equals(name)) {
// no-op this is valid 'name'
} else if("make".equals(name)) {
// this is a suggestion depends on your project conf
name = "vehicleMake.name";
} else {
continue; // ignore values we did not expect
}
// FIXME: You should validate all 'name' values
// to be valid and/or convert to Java property names here
System.out.println("name " + name);
System.out.println("value " + value);
this.queryParameters.put(name, sqlValue);
}
}
Criteria crit = this.session.createCriteria(Vehicle.class)
for(Map.Entry<String,Object> e : this.queryParameters.entrySet()) {
String n = e.getKey();
Object v = e.getValue();
// Sometimes you don't want a direct compare 'Restructions.eq()'
if("search".equals(n))
crit.add(Restrictions.like(n, "%" + v + "%"));
else // Most of the time you do
crit.add(Restrictions.eq(n, v));
}
this.vehicles = crit.list(); // run query
}
See also https://docs.jboss.org/hibernate/orm/3.5/reference/en/html/querycriteria.html
With the above there should be no risk of SQL injection, since the "name" and "n" part should be 100% validated against a known good list. The "value" and "v" is correctly escaped, just like using SQL position placeholder '?'.
E&OE
I would assume you would just loop over the parameters Map and add a Restriction for each pair.
Be aware that this will open you up to sql injection attacks if you are not careful. the easiest way to protect against this would be to check the keys against the known Vehicle properties before adding to the Criteria.
Another option would be to create an example query by building an object from the name/value pairs:
Vehicle vehicle = new Vehicle();
int count = context.getCount();
int i;
for (i = 0; (i + 1) < count; i += 2) {
String name = context.get(String.class, i);
String value = context.get(String.class, i + 1);
// This will call the setter for the name, passing the value
// So if name is 'make' and value is 'ford', it will call vehicle.setMake('ford')
BeantUtils.setProperty(vehicle, name, value);
}
// This is using a Hibernate example query:
vehicles = session.createCriteria(Vehicle.class).add(Example.create(vehicle)).list();
See BeanUtils.setProperty and Example Queries for more info.
That assumes you are allowing only one value per property and that the query parameters map to the property names correctly. There may also be conversion issues to think about but I think setProperty handles the common ones.
If they are query paramaters you should treat them as query parameters instead of path parameters. Your URL should look something like:
www.mywebsite.com/vehicles?make=ford&model=focus&year=2009
and your code should look something like this:
public class Vehicles {
#ActivationRequestParameter
private String make;
#ActivationRequestParameter
private String model;
#ActivationRequestParameter
private String year;
#Inject
private Session session;
#OnEvent(EventConstants.ACTIVATE)
void activate() {
Criteria criteria = session.createCriteria(Vehicle.class);
if (make != null) criteria.add(Restrictions.eq("make", make));
if (model != null) criteria.add(Restrictions.eq("model", model));
if (year != null) criteria.add(Restrictions.eq("year", year));
vehicles = criteria.list();
}
}
Assuming you are using the Grid component to display the vehicles I'd highly recommend using the HibernateGridDataSource instead of making the query in the "activate" event handler.
public class Vehicles {
#ActivationRequestParameter
private String make;
#ActivationRequestParameter
private String model;
#ActivationRequestParameter
private String year;
#Inject
private Session session;
#OnEvent(EventConstants.ACTIVATE)
void activate() {
}
public GridDataSource getVehicles() {
return new HibernateGridDataSource(session, Vehicles.class) {
#Override
protected void applyAdditionalConstraints(Criteria criteria) {
if (make != null) criteria.add(Restrictions.eq("make", make));
if (model != null) criteria.add(Restrictions.eq("model", model));
if (year != null) criteria.add(Restrictions.eq("year", year));
}
};
}
}

Get boolean from database using Android and SQLite

How can I obtain the value of a boolean field in an SQLite database on Android?
I usually use getString(), getInt(), etc. to get the values of my fields, but there does not seem to be a getBoolean() method.
It is:
boolean value = cursor.getInt(boolean_column_index) > 0;
There is no bool data type in SQLite. Use an int that you fix to 0 or 1 to achieve that effect. See the datatypes reference on SQLite 3.0.
boolean value = (cursor.getInt(boolean_column_index) == 1);
Most of the answers here can result in NumberFormatExceptions or "operator is undefined for the types null, int" if the column you stored the int in was allowed to also hold null.
The decent way to do this would be to use
Boolean.parseBoolean(cursor.getString(booleanColumnIndex));`
though you are now limited to storing the strings "true" and "false" rather than 0 or 1.
An implementation found at Ormlite Cursor also checks for Null which none of the other answers do.
public boolean getBoolean(int columnIndex) {
if (cursor.isNull(columnIndex) || cursor.getShort(columnIndex) == 0) {
return false;
} else {
return true;
}
}
You can also use
boolean value =cursor.getString(boolean_column_index).equals("True");
boolean datatype is not available in Cursor.
you will get the result in an int, so you need to convert that int value to a boolean.
You can either use
boolean b = cursor.getInt(boolean_column_index) > 0;
or
boolean b = (cursor.getInt(boolean_column_index) != 0);
Another option
boolean value = (cursor.getString(column_index)).equals("1");
boolean b = (cursor.getInt(cursor.getColumnIndex("item")) != 0);
Well, that's very simple:
public boolean getBooleanState(SQLiteDatabase db){
boolean result = false;
try{
String QUERY = "SELECT " + BOOLEAN_DATA + " FROM " + TABLE_NAME + " WHERE " + ID + " = 1";
Cursor cursor = db.rawQuery(QUERY, null);
if (cursor.moveToFirst()){
if(cursor.getString(0).equalsIgnoreCase("1")){
result = true;
}
}
c.close();
}catch(Exception ee){
Log.e(TAG, "err getBooleanState: " + TABLE_NAME );
}
return result;
}
For an optional (nullable) Boolean stored as INTEGER, you can create a Kotlin extension:
fun Cursor.getBoolean(columnIndex: Int): Boolean? {
return if (isNull(columnIndex))
null
else
getInt(columnIndex) != 0
}
and use it like this:
val value: Boolean? = cursor.getBoolean(boolean_column_index)
thats what I used:
val work = Work()
work.id = cursor.getInt(0)
work.date = cursor.getString(1)
work.work_value = cursor.getFloat(2)
work.place = cursor.getString(3)
work.wind = cursor.getFloat(4)
work.isCompetition = cursor.getInt(5) > 0
return work
I face the same thing in kotlin.
There was the value "true/false" in the database
and I access it with this code:
cursor.getString(4).toBoolean()
//first as a string then converting them to boolean

Java toString() using reflection?

I was writing a toString() for a class in Java the other day by manually writing out each element of the class to a String and it occurred to me that using reflection it might be possible to create a generic toString() method that could work on ALL classes. I.E. it would figure out the field names and values and send them out to a String.
Getting the field names is fairly simple, here is what a co-worker came up with:
public static List initFieldArray(String className) throws ClassNotFoundException {
Class c = Class.forName(className);
Field field[] = c.getFields();
List<String> classFields = new ArrayList(field.length);
for (int i = 0; i < field.length; i++) {
String cf = field[i].toString();
classFields.add(cf.substring(cf.lastIndexOf(".") + 1));
}
return classFields;
}
Using a factory I could reduce the performance overhead by storing the fields once, the first time the toString() is called. However finding the values could be a lot more expensive.
Due to the performance of reflection this may be more hypothetical then practical. But I am interested in the idea of reflection and how I can use it to improve my everyday programming.
Apache commons-lang ReflectionToStringBuilder does this for you.
import org.apache.commons.lang3.builder.ReflectionToStringBuilder
// your code goes here
public String toString() {
return ReflectionToStringBuilder.toString(this);
}
Another option, if you are ok with JSON, is Google's GSON library.
public String toString() {
return new GsonBuilder().setPrettyPrinting().create().toJson(this);
}
It's going to do the reflection for you. This produces a nice, easy to read JSON file. Easy-to-read being relative, non tech folks might find the JSON intimidating.
You could make the GSONBuilder a member variable too, if you don't want to new it up every time.
If you have data that can't be printed (like a stream) or data you just don't want to print, you can just add #Expose tags to the attributes you want to print and then use the following line.
new GsonBuilder()
.setPrettyPrinting()
.excludeFieldsWithoutExposeAnnotation()
.create()
.toJson(this);
W/reflection, as I hadn't been aware of the apache library:
(be aware that if you do this you'll probably need to deal with subobjects and make sure they print properly - in particular, arrays won't show you anything useful)
#Override
public String toString()
{
StringBuilder b = new StringBuilder("[");
for (Field f : getClass().getFields())
{
if (!isStaticField(f))
{
try
{
b.append(f.getName() + "=" + f.get(this) + " ");
} catch (IllegalAccessException e)
{
// pass, don't print
}
}
}
b.append(']');
return b.toString();
}
private boolean isStaticField(Field f)
{
return Modifier.isStatic(f.getModifiers());
}
If you're using Eclipse, you may also have a look at JUtils toString generator, which does it statically (generating the method in your source code).
You can use already implemented libraries, as ReflectionToStringBuilder from Apache commons-lang. As was mentioned.
Or write smt similar by yourself with reflection API.
Here is some example:
class UniversalAnalyzer {
private ArrayList<Object> visited = new ArrayList<Object>();
/**
* Converts an object to a string representation that lists all fields.
* #param obj an object
* #return a string with the object's class name and all field names and
* values
*/
public String toString(Object obj) {
if (obj == null) return "null";
if (visited.contains(obj)) return "...";
visited.add(obj);
Class cl = obj.getClass();
if (cl == String.class) return (String) obj;
if (cl.isArray()) {
String r = cl.getComponentType() + "[]{";
for (int i = 0; i < Array.getLength(obj); i++) {
if (i > 0) r += ",";
Object val = Array.get(obj, i);
if (cl.getComponentType().isPrimitive()) r += val;
else r += toString(val);
}
return r + "}";
}
String r = cl.getName();
// inspect the fields of this class and all superclasses
do {
r += "[";
Field[] fields = cl.getDeclaredFields();
AccessibleObject.setAccessible(fields, true);
// get the names and values of all fields
for (Field f : fields) {
if (!Modifier.isStatic(f.getModifiers())) {
if (!r.endsWith("[")) r += ",";
r += f.getName() + "=";
try {
Class t = f.getType();
Object val = f.get(obj);
if (t.isPrimitive()) r += val;
else r += toString(val);
} catch (Exception e) {
e.printStackTrace();
}
}
}
r += "]";
cl = cl.getSuperclass();
} while (cl != null);
return r;
}
}
Not reflection, but I had a look at generating the toString method (along with equals/hashCode) as a post-compilation step using bytecode manipulation. Results were mixed.
Here is the Netbeans equivalent to Olivier's answer; smart-codegen plugin for Netbeans.

Categories