How to validate an input string with few fields in the enum - java

I have my below enum -
public enum TestEnum {
h1, h2, h3, h4;
public static String forCode(int code) {
return (code >= 0 && code < values().length) ? values()[code].name() : null;
}
public static void main(String[] args) {
System.out.println(TestEnum.h1.name());
String ss = "h3";
try {
TestEnum.valueOf(ss); // but this validates with all the enum values
System.out.println("valid");
} catch (IllegalArgumentException e) {
System.out.println("invalid");
}
}
}
I need to compare string ss only with h1 , h2 or h4 in the enum..
Meaning if h3 is being passed as a string, I would like to return false or throw IllegalArgumntException.
I won't need to validate ss with h3 in the enum.. How would I do this using the enum?

I believe there is more elegant solution but as for now I would solve it this way:
import java.util.Arrays;
public enum TestEnum {
h1, h2, h3, h4;
public static boolean checkExcept(String el, TestEnum... except){
boolean results = false;
try{
results = !Arrays.asList(except).contains(TestEnum.valueOf(el));
}catch (Exception e){}
return results;
}
public static String forCode(int code) {
return (code >= 0 && code < values().length) ? values()[code].name() : null;
}
public static void main(String[] args) {
String ss = "h3";
if(TestEnum.checkExcept(ss,TestEnum.h1, TestEnum.h2, TestEnum.h3)){
System.out.println("valid");
}else{
System.out.println("invalid");
}
ss = "h1";
if(TestEnum.checkExcept(ss,TestEnum.h2)){
System.out.println("valid");
}else{
System.out.println("invalid");
}
ss = "h2";
if(TestEnum.checkExcept(ss,TestEnum.h2)){
System.out.println("valid");
}else{
System.out.println("invalid");
}
}
}
PS: You can implement checkOnly to use whitelist instead.

You can validate like this:
ss.equals("h3")
or in a more convoluted way:
ss.equals(h3.toString())

Related

Reduce code duplication when reading different types of numbers from console

I have created three methods readLong, readInt and readDouble that basically does the same thing. Only difference is the method called by a scanner. How can I reduce duplicate code by turning them all to one method?
public long readLong(String description)
{
System.out.println(description);
long nrToReturn = 0;
boolean acceptedValue = false;
do {
System.out.println();
System.out.print("Choose one: ");
try
{
nrToReturn = consoleScanner.nextLong(); //Only line thats different except return value
acceptedValue = true;
}catch(Exception e)
{
acceptedValue = false;
consoleScanner.nextLine();
}
}while (!acceptedValue);
consoleScanner.nextLine();
return nrToReturn;
}
Here we go with one idea:
import java.util.Scanner;
public class ScannerTest {
private Scanner consoleScanner;
public ScannerTest() {
consoleScanner = new Scanner(System.in);
}
#SuppressWarnings("unchecked")
private <T extends Number> T readType(String description, Class<T> desiredType) {
System.out.println(description);
Number result = null;
while (result == null) {
System.out.println();
System.out.print("Choose one: ");
try {
if (Integer.class.equals(desiredType)) {
result = new Integer(consoleScanner.nextInt());
} else if (Long.class.equals(desiredType)) {
result = new Long(consoleScanner.nextLong());
}
} catch(Exception e) {
consoleScanner.nextLine();
}
}
consoleScanner.nextLine();
return (T) result;
}
public long readLong(String description) {
return this.readType(description, Long.class);
}
public int readInt(String description) {
return this.readType(description, Integer.class);
}
public static void main(String[] args) {
ScannerTest t = new ScannerTest();
t.readLong("Reading a long value...");
t.readInt("Reading an integer value...");
}
}
Update, following #Michu93 idea of a single transparent method:
import java.util.Scanner;
public class ScannerTest {
private Scanner consoleScanner;
public ScannerTest() {
consoleScanner = new Scanner(System.in);
}
#SuppressWarnings("unchecked")
public <T extends Number> T readNumber(String description) {
System.out.println(description);
Number result = null;
while (result == null) {
System.out.print("\nChoose one: ");
String textRead = consoleScanner.next();
try {
result = new Integer(textRead);
} catch(Exception e1) {
try {
result = new Long(textRead);
} catch (Exception e2) {
try {
result = new Double(textRead);
} catch (Exception e3) {
}
}
}
consoleScanner.nextLine();
}
return (T) result;
}
public static void main(String[] args) {
ScannerTest t = new ScannerTest();
for (int i = 0; i < 3; i++) {
Number input = t.readNumber(i + ": Reading int, long or double...");
System.out.println("Input class: " + input.getClass().getCanonicalName());
System.out.println("Input value: " + input);
}
}
}

How to eliminate repeat code in a for-loop?

I have implemented two member functions in the same class:
private static void getRequiredTag(Context context) throws IOException
{
//repeated begin
for (Record record : context.getContext().readCacheTable("subscribe")) {
String traceId = record.get("trace_id").toString();
if (traceSet.contains(traceId) == false)
continue;
String tagId = record.get("tag_id").toString();
try {
Integer.parseInt(tagId);
} catch (NumberFormatException e) {
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
//repeated end
tagSet.add(tagId);
}
}
private static void addTagToTraceId(Context context) throws IOException
{
//repeated begin
for (Record record : context.getContext().readCacheTable("subscribe")) {
String traceId = record.get("trace_id").toString();
if (traceSet.contains(traceId) == false)
continue;
String tagId = record.get("tag_id").toString();
try {
Integer.parseInt(tagId);
} catch (NumberFormatException e) {
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
//repeated end
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}
}
I will call that two member functions in another two member functions(so I can't merge them into one function):
private static void A()
{
getRequiredTag()
}
private static void B()
{
getRequiredTag()
addTagToTraceId()
}
tagSet is java.util.Set and traceListMap is java.util.Map.
I know DRY principle and I really want to eliminate the repeat code, so I come to this code:
private static void getTraceIdAndTagIdFromRecord(Record record, String traceId, String tagId) throws IOException
{
traceId = record.get("trace_id").toString();
tagId = record.get("tag_id").toString();
}
private static boolean checkTagIdIsNumber(String tagId)
{
try {
Integer.parseInt(tagId);
} catch (NumberFormatException e) {
return false;
}
return true;
}
private static void getRequiredTag(Context context) throws IOException
{
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
tagSet.add(tagId);
}
}
private static void addTagToTraceId(Context context) throws IOException
{
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}
}
It seems I got an new repeat... I have no idea to eliminate repeat in that case, could anybody give me some advice?
update 2015-5-13 21:15:12:
Some guys gives a boolean argument to eliminate repeat, but I know
Robert C. Martin's Clean Code Tip #12: Eliminate Boolean Arguments.(you can google it for more details).
Could you gives some comment about that?
The parts that changes requires the values of String tagId and String traceId so we will start by extracting an interface that takes those parameters:
public static class PerformingInterface {
void accept(String tagId, String traceId);
}
Then extract the common parts into this method:
private static void doSomething(Context context, PerformingInterface perform) throws IOException
{
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
perform.accept(tagId, traceId);
}
}
Then call this method in two different ways:
private static void getRequiredTag(Context context) throws IOException {
doSomething(context, new PerformingInterface() {
#Override public void accept(String tagId, String traceId) {
tagSet.add(tagId);
}
});
}
private static void addTagToTraceId(Context context) throws IOException {
doSomething(context, new PerformingInterface() {
#Override public void accept(String tagId, String traceId) {
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}
});
}
Note that I am using lambdas here, which is a Java 8 feature (BiConsumer is also a functional interface defined in Java 8), but it is entirely possible to accomplish the same thing in Java 7 and less, it just requires some more verbose code.
Some other issues with your code:
Way too many things is static
The Vector class is old, it is more recommended to use ArrayList (if you need synchronization, wrap it in Collections.synchronizedList)
Always use braces, even for one-liners
You could use a stream (haven't tested):
private static Stream<Record> validRecords(Context context) throws IOException {
return context.getContext().readCacheTable("subscribe").stream()
.filter(r -> {
if (!traceSet.contains(traceId(r))) {
return false;
}
try {
Integer.parseInt(tagId(r));
return true;
} catch (NumberFormatException e) {
context.getCounter("Error", "tag_id not a number").increment(1);
return false;
}
});
}
private static String traceId(Record record) {
return record.get("trace_id").toString();
}
private static String tagId(Record record) {
return record.get("tag_id").toString();
}
Then could do just:
private static void getRequiredTag(Context context) throws IOException {
validRecords(context).map(r -> tagId(r)).forEach(tagSet::add);
}
private static void addTagToTraceId(Context context) throws IOException {
validRecords(context).forEach(r -> {
String tagId = tagId(r);
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId(r));
traceListMap.put(tagId, ret);
});
}
tagId seems to be always null in your second attempt.
Nevertheless, one approach would be to extract the code that collects tagIds (this seems to be the same in both methods) into its own method. Then, in each of the two methods just iterate over the collection of returned tagIds and do different operations on them.
for (String tagId : getTagIds(context)) {
// do method specific logic
}
EDIT
Now I noticed that you also use traceId in the second method. The principle remains the same, just collect Records in a separate method and iterate over them in the two methods (by taking tagId and traceId from records).
Solution with lambdas is the most elegant one, but without them it involves creation of separate interface and two anonymous classes which is too verbose for this use case (honestly, here I would rather go with a boolean argument than with a strategy without lambdas).
Try this approach
private static void imYourNewMethod(Context context,Boolean isAddTag){
String traceId = null, tagId = null;
for (Record record : context.getContext().readCacheTable("subscribe")) {
getTraceIdAndTagIdFromRecord(record, traceId, tagId);
if (traceSet.contains(traceId) == false)
continue;
if (!checkTagIdIsNumber(tagId))
{
context.getCounter("Error", "tag_id not a number").increment(1);
continue;
}
if(isAddTag){
Vector<String> ret = traceListMap.get(tagId);
if (ret == null) {
ret = new Vector<String>();
}
ret.add(traceId);
traceListMap.put(tagId, ret);
}else{
tagSet.add(tagId);
}
}
call this method and pass one more parameter boolean true if you want to add otherwise false to get it.

Is it possible to evaluate a boolean expression for String comparions?

I will have a String like
('abc' != 'xyz' AND 'thy' = 'thy') OR ('ujy' = 'ujy')
The String will be able to have as many "AND" groups as it wants. There will not be any nested groups within the AND groups. All groups will ALWAYS be serparated by an OR.
I can just switch out the AND for && and OR for ||.
What I would like is to pass this String into some type of eval method and output TRUE or FALSE.
Is there anything out there that can do this?
You can use the built-in Javascript engine coming with the JDK1.6 to evaluate string containing math expressions.
You an give a lookup here: ScriptEngine
Here an example:
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
public class Myclass {
public static void main(String[] args) {
try {
ScriptEngineManager sem = new ScriptEngineManager();
ScriptEngine se = sem.getEngineByName("JavaScript");
String myExpression = "('abc' == 'xyz' && 'thy' == 'thy') || ('ujy' == 'ujy')";
System.out.println(se.eval(myExpression));
} catch (ScriptException e) {
System.out.println("Invalid Expression");
e.printStackTrace();
}
}
}
Just remember to replace the following:
'AND' with '&&',
'OR' with '||',
'=' must be '=='
Otherwise it will not accept your expression and will throws a javax.script.ScriptException
you can use script package to achieve this like
ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("js");
String[] vars = {"var1 = 'xyz'", "var2 = 'xyz'"};
try {
for (String var : vars) {
engine.eval(var);
}
System.out.println(engine.eval("var1 == var2 "));
} catch (ScriptException e) {
e.printStackTrace();
}
I think you have to parse it and write custom classes for it like this
public interface StringEquals{
public boolean equals(String s1, String s2);
}
public class Equals implements StringEquals{
private String mS1;
private STring mS2;
public NotEquals(String s1, String s2){
mS1 = s1;
mS2 = s2;
}
public boolean equals(){
return mSq1.equals(mS2);
}
}
public class NotEquals implements StringEquals{
private String mS1;
private STring mS2;
public NotEquals(String s1, String s2){
mS1 = s1;
mS2 = s2;
}
public boolean equals(){
return !mS1.equals(mS2);
}
}
public class AndGroup{
private List<StringEquals> mStrings;
public AndGroup(List<StringEquals> list){
mStrings = list;
}
public boolean getResult(){
for(StringEquals e: mStrings){
if (!e.equals()){
return false;
}
}
return true;
}
and a class to parse it:
public boolean eval(String evalString){
List<AndGroup> groups = new LinkedList<AndGroup>();
String[] ands = evalString.split("OR");
for (String andExp : ands){
List<StringEquals> list = new LinkedList<StringEquals>();
String compares = andExp.split("AND");
for (String comp: compares){
if (comp.contains("!="){
String[] notEqual = comp.split("!=");
list.add(new NotEquals(notEqual[0], notEqual[1]));
} else {
String[] equal = comp.split("=");
list.add(new Equals(equal[0], equal[1]);
}
}
groups.add(new AndGroup(list));
}
for (AndGroup g: groups){
if (g.getResult()){
return true;
}
}
return false;
}
not tested, but it may point you into the right direction
I think you can try groovy (if it's an option for you) with it's groovy.util.Eval, but first you should process your string and replace AND\OR with && and ||.

Java Reflection to set Value for the java pojo

Goal :
set value for the given java bean at run time and generate JSON Object or JSON array.
the above is my goal and i have tried some thing like the below :
package com.hexgen.tools;
import java.lang.reflect.Method;
import com.google.gson.Gson;
public class ConvertPOJOToJSON {
public Object creatJSONObject(String className) throws IllegalArgumentException, IllegalAccessException, InstantiationException, Exception {
Class<?> objectClass = null;
Object clsObject =null;
try {
objectClass = Class.forName(className);
clsObject = objectClass.newInstance();
for(Method m : objectClass.getMethods())
if (m.getName().startsWith("set") && m.getParameterTypes().length == 1 && m.getModifiers()==23)
m.invoke(clsObject, "myValue");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return clsObject;
}
public static void main(String[] args) {
Gson gson = new Gson();
ConvertPOJOToJSON pojoToJSON = new ConvertPOJOToJSON();
try {
System.out.println("JSON OBJECT : "+gson.toJson(pojoToJSON.creatJSONObject("com.hexgen.ro.request.CreateRequisitionRO")));
} catch (Exception e) {
e.printStackTrace();
}
}
}
The Output of the above class :
JSON OBJECT : {"isAllocable":false}
there are many fields in the class i gave com.hexgen.ro.request.CreateRequisitionRO but only one boolean value is set to false and returns the value.
i have some constant value to set for the fields say if the field type is Integer than set some default integer value like so
EDIT :
I have created a enum like the following :
package com.hexgen.tools;
import java.math.BigDecimal;
import java.math.BigInteger;
import org.joda.time.LocalDate;
public enum DefaultParamValues {
STRING("HEXGEN"),
INTEGER(123),
DATE(new LocalDate()),
BOOLEAN(true),
LONGVALUE(123123),
BIGDECIMAL(new BigDecimal("100000"));
private String defaultString;
private int defaultInteger;
private LocalDate defaultDate;
private boolean defaultBoolean;
private long defaultLong;
private BigDecimal defaultBigDecimal;
private DefaultParamValues(String strDefaultValue) {
defaultString = strDefaultValue;
}
private DefaultParamValues(int intDefaultValue) {
defaultInteger = intDefaultValue;
}
private DefaultParamValues(LocalDate dateDefaultValue) {
defaultDate = dateDefaultValue;
}
private DefaultParamValues(boolean booleanDefaultValue) {
defaultBoolean = booleanDefaultValue;
}
private DefaultParamValues(long longDefaultValue) {
defaultLong = longDefaultValue;
}
private DefaultParamValues(BigDecimal bigIntegerDefaultValue) {
defaultBigDecimal = bigIntegerDefaultValue;
}
public String getDefaultString() {
return defaultString;
}
public int getDefaultInt() {
return defaultInteger;
}
public LocalDate getDefaultDate() {
return defaultDate;
}
public boolean getDefaultBoolean() {
return defaultBoolean;
}
public long getDefaultLong() {
return defaultLong;
}
public BigDecimal getDdefaultBigDecimal() {
return defaultBigDecimal;
}
}
created one more method like the following :
public Object creatObjectWithDefaultValue(String className) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
DefaultParamValues defaultParamValues = null;
Class<?> objectClass = null;
Object clsObject =null;
try {
objectClass = Class.forName(className);
clsObject = objectClass.newInstance();
Field[] fields = objectClass.getDeclaredFields();
for(Field f:fields){
if(!f.isAccessible()){
f.setAccessible(true);
Class<?> type = f.getType();
if(! Modifier.isFinal(f.getModifiers()) && type.equals(Integer.class)){
f.set(clsObject, defaultParamValues.INTEGER);
} else if( !Modifier.isFinal(f.getModifiers()) && type.equals(java.math.BigDecimal.class)){
f.set(clsObject, defaultParamValues.BIGDECIMAL);
} else if(! Modifier.isFinal(f.getModifiers()) && type.equals(org.joda.time.LocalDate.class)){
f.set(clsObject,defaultParamValues.DATE);
} else if(! Modifier.isFinal(f.getModifiers()) && type.equals(boolean.class)){
f.set(clsObject, defaultParamValues.BOOLEAN);
} else if(! Modifier.isFinal(f.getModifiers()) && type.equals(java.lang.String.class)){
f.set(clsObject, defaultParamValues.STRING);
}
else if(! Modifier.isFinal(f.getModifiers()) && type.equals(long.class)){
f.set(clsObject, defaultParamValues.LONGVALUE);
}
//f.setAccessible(false);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return clsObject;
}
to set the default values but i get the following exception:
Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.math.BigDecimal field com.hexgen.ro.request.CreateRequisitionRO.transSrlNo to com.hexgen.tools.DefaultParamValues
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150)
at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63)
at java.lang.reflect.Field.set(Field.java:657)
at com.hexgen.tools.JsonConverter.creatObjectWithDefaultValue(JsonConverter.java:93)
at com.hexgen.tools.JsonConverter.main(JsonConverter.java:201)
Please help me to find the solution.
Best Regards
If your looking for a lightweight library which can do this and more including allowing you to do your own filtering to find Methods/Fields. I wrote an open source library which has no 3rd party dependencies and is available on Maven Central.
Checkout https://github.com/gondor/reflect
As for your issue it appears your setting the "Enum" constant and not the inner value of the enum. Wouldn't it DefaultParamValues.BIGDECIMAL.getDdefaultBigDecimal()

Printing all variables value from a class

I have a class with information about a Person that looks something like this:
public class Contact {
private String name;
private String location;
private String address;
private String email;
private String phone;
private String fax;
public String toString() {
// Something here
}
// Getters and setters.
}
I want toString() to return this.name +" - "+ this.locations + ... for all variables. I was trying to implement it using reflection as shown from this question but I can't manage to print instance variables.
What is the correct way to solve this?
From Implementing toString:
public String toString() {
StringBuilder result = new StringBuilder();
String newLine = System.getProperty("line.separator");
result.append( this.getClass().getName() );
result.append( " Object {" );
result.append(newLine);
//determine fields declared in this class only (no fields of superclass)
Field[] fields = this.getClass().getDeclaredFields();
//print field names paired with their values
for ( Field field : fields ) {
result.append(" ");
try {
result.append( field.getName() );
result.append(": ");
//requires access to private field:
result.append( field.get(this) );
} catch ( IllegalAccessException ex ) {
System.out.println(ex);
}
result.append(newLine);
}
result.append("}");
return result.toString();
}
Why do you want to reinvent the wheel when there are opensource that are already doing the job pretty nicely.
Both apache common-langs and spring support some very flexible builder pattern
For apache, here is how you do it reflectively
#Override
public String toString()
{
return ToStringBuilder.reflectionToString(this);
}
Here is how you do it if you only want to print fields that you care about.
#Override
public String toString()
{
return new ToStringBuilder(this)
.append("name", name)
.append("location", location)
.append("address", address)
.toString();
}
You can go as far as "styling" your print output with non-default ToStringStyle or even customizing it with your own style.
I didn't personally try spring ToStringCreator api, but it looks very similar.
If you are using Eclipse, this should be easy:
1.Press Alt+Shift+S
2.Choose "Generate toString()..."
Enjoy! You can have any template of toString()s.
This also works with getter/setters.
Generic toString() one-liner, using reflection and style customization:
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
...
public String toString()
{
return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}
When accessing the field value, pass the instance rather than null.
Why not use code generation here? Eclipse, for example, will generate a reasoble toString implementation for you.
Another simple approach is to let Lombok generate the toString method for you.
For this:
Simply add Lombok to your project
Add the annotation #ToString to the definition of your class
Compile your class/project, and it is done
So for example in your case, your class would look like this:
#ToString
public class Contact {
private String name;
private String location;
private String address;
private String email;
private String phone;
private String fax;
// Getters and setters.
}
Example of output in this case:
Contact(name=John, location=USA, address=SF, email=foo#bar.com, phone=99999, fax=88888)
More details about how to use the annotation #ToString.
NB: You can also let Lombok generate the getters and setters for you, here is the full feature list.
If the output from ReflectionToStringBuilder.toString() is not enough readable for you, here is code that:
1) sorts field names alphabetically
2) flags non-null fields with asterisks in the beginning of the line
public static Collection<Field> getAllFields(Class<?> type) {
TreeSet<Field> fields = new TreeSet<Field>(
new Comparator<Field>() {
#Override
public int compare(Field o1, Field o2) {
int res = o1.getName().compareTo(o2.getName());
if (0 != res) {
return res;
}
res = o1.getDeclaringClass().getSimpleName().compareTo(o2.getDeclaringClass().getSimpleName());
if (0 != res) {
return res;
}
res = o1.getDeclaringClass().getName().compareTo(o2.getDeclaringClass().getName());
return res;
}
});
for (Class<?> c = type; c != null; c = c.getSuperclass()) {
fields.addAll(Arrays.asList(c.getDeclaredFields()));
}
return fields;
}
public static void printAllFields(Object obj) {
for (Field field : getAllFields(obj.getClass())) {
field.setAccessible(true);
String name = field.getName();
Object value = null;
try {
value = field.get(obj);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
System.out.printf("%s %s.%s = %s;\n", value==null?" ":"*", field.getDeclaringClass().getSimpleName(), name, value);
}
}
test harness:
public static void main(String[] args) {
A a = new A();
a.x = 1;
B b = new B();
b.x=10;
b.y=20;
System.out.println("=======");
printAllFields(a);
System.out.println("=======");
printAllFields(b);
System.out.println("=======");
}
class A {
int x;
String z = "z";
Integer b;
}
class B extends A {
int y;
private double z = 12345.6;
public int a = 55;
}
Addition with #cletus answer, You have to fetch all model fields(upper hierarchy) and set field.setAccessible(true) to access private members. Here is the full snippet:
#Override
public String toString() {
StringBuilder result = new StringBuilder();
String newLine = System.getProperty("line.separator");
result.append(getClass().getSimpleName());
result.append( " {" );
result.append(newLine);
List<Field> fields = getAllModelFields(getClass());
for (Field field : fields) {
result.append(" ");
try {
result.append(field.getName());
result.append(": ");
field.setAccessible(true);
result.append(field.get(this));
} catch ( IllegalAccessException ex ) {
// System.err.println(ex);
}
result.append(newLine);
}
result.append("}");
result.append(newLine);
return result.toString();
}
private List<Field> getAllModelFields(Class aClass) {
List<Field> fields = new ArrayList<>();
do {
Collections.addAll(fields, aClass.getDeclaredFields());
aClass = aClass.getSuperclass();
} while (aClass != null);
return fields;
}
i will get my answer as follow:
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class findclass {
public static void main(String[] args) throws Exception, IllegalAccessException {
new findclass().findclass(new Object(), "objectName");
new findclass().findclass(1213, "int");
new findclass().findclass("ssdfs", "String");
}
public Map<String, String>map=new HashMap<String, String>();
public void findclass(Object c,String name) throws IllegalArgumentException, IllegalAccessException {
if(map.containsKey(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))){
System.out.println(c.getClass().getSimpleName()+" "+name+" = "+map.get(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))+" = "+c);
return;}
map.put(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()), name);
Class te=c.getClass();
if(te.equals(Integer.class)||te.equals(Double.class)||te.equals(Float.class)||te.equals(Boolean.class)||te.equals(Byte.class)||te.equals(Long.class)||te.equals(String.class)||te.equals(Character.class)){
System.out.println(c.getClass().getSimpleName()+" "+name+" = "+c);
return;
}
if(te.isArray()){
if(te==int[].class||te==char[].class||te==double[].class||te==float[].class||te==byte[].class||te==long[].class||te==boolean[].class){
boolean dotflag=true;
for (int i = 0; i < Array.getLength(c); i++) {
System.out.println(Array.get(c, i).getClass().getSimpleName()+" "+name+"["+i+"] = "+Array.get(c, i));
}
return;
}
Object[]arr=(Object[])c;
for (Object object : arr) {
if(object==null)
System.out.println(c.getClass().getSimpleName()+" "+name+" = null");
else {
findclass(object, name+"."+object.getClass().getSimpleName());
}
}
}
Field[] fields=c.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if(field.get(c)==null){
System.out.println(field.getType().getSimpleName()+" "+name+"."+field.getName()+" = null");
continue;
}
findclass(field.get(c),name+"."+field.getName());
}
if(te.getSuperclass()==Number.class||te.getSuperclass()==Object.class||te.getSuperclass()==null)
return;
Field[]faFields=c.getClass().getSuperclass().getDeclaredFields();
for (Field field : faFields) {
field.setAccessible(true);
if(field.get(c)==null){
System.out.println(field.getType().getSimpleName()+" "+name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName()+" = null");
continue;
}
Object check=field.get(c);
findclass(field.get(c),name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName());
}
}
public void findclass(Object c,String name,Writer writer) throws IllegalArgumentException, IllegalAccessException, IOException {
if(map.containsKey(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))){
writer.append(c.getClass().getSimpleName()+" "+name+" = "+map.get(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()))+" = "+c+"\n");
return;}
map.put(c.getClass().getName() + "#" + Integer.toHexString(c.hashCode()), name);
Class te=c.getClass();
if(te.equals(Integer.class)||te.equals(Double.class)||te.equals(Float.class)||te.equals(Boolean.class)||te.equals(Byte.class)||te.equals(Long.class)||te.equals(String.class)||te.equals(Character.class)){
writer.append(c.getClass().getSimpleName()+" "+name+" = "+c+"\n");
return;
}
if(te.isArray()){
if(te==int[].class||te==char[].class||te==double[].class||te==float[].class||te==byte[].class||te==long[].class||te==boolean[].class){
boolean dotflag=true;
for (int i = 0; i < Array.getLength(c); i++) {
writer.append(Array.get(c, i).getClass().getSimpleName()+" "+name+"["+i+"] = "+Array.get(c, i)+"\n");
}
return;
}
Object[]arr=(Object[])c;
for (Object object : arr) {
if(object==null){
writer.append(c.getClass().getSimpleName()+" "+name+" = null"+"\n");
}else {
findclass(object, name+"."+object.getClass().getSimpleName(),writer);
}
}
}
Field[] fields=c.getClass().getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
if(field.get(c)==null){
writer.append(field.getType().getSimpleName()+" "+name+"."+field.getName()+" = null"+"\n");
continue;
}
findclass(field.get(c),name+"."+field.getName(),writer);
}
if(te.getSuperclass()==Number.class||te.getSuperclass()==Object.class||te.getSuperclass()==null)
return;
Field[]faFields=c.getClass().getSuperclass().getDeclaredFields();
for (Field field : faFields) {
field.setAccessible(true);
if(field.get(c)==null){
writer.append(field.getType().getSimpleName()+" "+name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName()+" = null"+"\n");
continue;
}
Object check=field.get(c);
findclass(field.get(c),name+"<"+c.getClass().getSuperclass().getSimpleName()+"."+field.getName(),writer);
}
}
}

Categories