Reflection generic get field value - java

I am trying to obtain a field's value via reflection. The problem is I don't know the field's type and have to decide it while getting the value.
This code results with this exception:
Can not set java.lang.String field com....fieldName to java.lang.String
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Class<?> targetType = field.getType();
Object objectValue = targetType.newInstance();
Object value = field.get(objectValue);
I tried to cast, but I get compilation errors:
field.get((targetType)objectValue)
or
targetType objectValue = targetType.newInstance();
How can I do this?

Like answered before, you should use:
Object value = field.get(objectInstance);
Another way, which is sometimes prefered, is calling the getter dynamically. example code:
public static Object runGetter(Field field, BaseValidationObject o)
{
// MZ: Find the correct method
for (Method method : o.getMethods())
{
if ((method.getName().startsWith("get")) && (method.getName().length() == (field.getName().length() + 3)))
{
if (method.getName().toLowerCase().endsWith(field.getName().toLowerCase()))
{
// MZ: Method found, run it
try
{
return method.invoke(o);
}
catch (IllegalAccessException e)
{
Logger.fatal("Could not determine method: " + method.getName());
}
catch (InvocationTargetException e)
{
Logger.fatal("Could not determine method: " + method.getName());
}
}
}
}
return null;
}
Also be aware that when your class inherits from another class, you need to recursively determine the Field. for instance, to fetch all Fields of a given class;
for (Class<?> c = someClass; c != null; c = c.getSuperclass())
{
Field[] fields = c.getDeclaredFields();
for (Field classField : fields)
{
result.add(classField);
}
}

You should pass the object to get method of the field, so
Field field = object.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
Object value = field.get(object);

I use the reflections in the toString() implementation of my preference class to see the class members and values (simple and quick debugging).
The simplified code I'm using:
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
Class<?> thisClass = null;
try {
thisClass = Class.forName(this.getClass().getName());
Field[] aClassFields = thisClass.getDeclaredFields();
sb.append(this.getClass().getSimpleName() + " [ ");
for(Field f : aClassFields){
String fName = f.getName();
sb.append("(" + f.getType() + ") " + fName + " = " + f.get(this) + ", ");
}
sb.append("]");
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}
I hope that it will help someone, because I also have searched.

Although it's not really clear to me what you're trying to achieve, I spotted an obvious error in your code:
Field.get() expects the object which contains the field as argument, not some (possible) value of that field. So you should have field.get(object).
Since you appear to be looking for the field value, you can obtain that as:
Object objectValue = field.get(object);
No need to instantiate the field type and create some empty/default value; or maybe there's something I missed.

Integer typeValue = 0;
try {
Class<Types> types = Types.class;
java.lang.reflect.Field field = types.getDeclaredField("Type");
field.setAccessible(true);
Object value = field.get(types);
typeValue = (Integer) value;
} catch (Exception e) {
e.printStackTrace();
}

`
//Here is the example I used for get the field name also the field value
//Hope This will help to someone
TestModel model = new TestModel ("MyDate", "MyTime", "OUT");
//Get All the fields of the class
Field[] fields = model.getClass().getDeclaredFields();
//If the field is private make the field to accessible true
fields[0].setAccessible(true);
//Get the field name
System.out.println(fields[0].getName());
//Get the field value
System.out.println(fields[0].get(model));
`

I post my solution in Kotlin, but it can work with java objects as well.
I create a function extension so any object can use this function.
fun Any.iterateOverComponents() {
val fields = this.javaClass.declaredFields
fields.forEachIndexed { i, field ->
fields[i].isAccessible = true
// get value of the fields
val value = fields[i].get(this)
// print result
Log.w("Msg", "Value of Field "
+ fields[i].name
+ " is " + value)
}}
Take a look at this webpage: https://www.geeksforgeeks.org/field-get-method-in-java-with-examples/

Was able to access private fields in a class using following method
Beneficiary ben = new Beneficiary();//class with multiple fields
ben.setName("Ashok");//is set by a setter
//then to get that value following was the code which worked for me
Field[] fields = ben.getClass().getDeclaredFields();
for(Field field: fields) {
field.setAccessible(true);//to access private fields
System.out.println(field.get(ben));//to get value
//assign value for the same field.set(ben, "Y");//to set value
}

You are calling get with the wrong argument.
It should be:
Object value = field.get(object);

Related

Java reflection - get field value

I try make class which generate new className.java file using reflection. I have problem with Fields value.
Here is my test class.
public class ClassTest {
#Deprecated
private int a;
public int[] b;
private final String c = "Hi";
...
}
Method in which I try generate fields.
private void writeAttributes(Class<?> cls, PrintWriter writer){
Field[] atr = cls.getDeclaredFields();
for (Field field : atr) {
this.writeAnnotations(writer, field.getDeclaredAnnotations());
writer.write(Modifier.toString(field.getModifiers())+" " + field.getType().getTypeName()+ " " + field.getName());
try{
System.out.println(field);
// NULL POINTER EXCEPTION there
Object value = field.get(null);
if(value!= null){
writer.write(" = " + value.toString());
}
}catch(IllegalAccessException ex){
}
writer.write(";");
this.writeNewLine(writer);
}
}
Error is on third field private final String c = "Hi";
Exception in thread "main" java.lang.NullPointerException
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:57)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
I have tried add field.setAccessible(true); but with there error comes on second field. Any ideas what is bad?
Since this is an instance field, you will need to pass an instance of the class to the get method:
get(clsInstance);
The documentation is actually pretty clear about that:
Throws NullPointerException - if the specified object is null and the field is an instance field.
You cannot access private fields by using .getDeclaredFields(). You can only access the public fields.

Is there a common Java method to trim every string in an object graph?

I'm hoping to trim all Strings that are part of an object graph.
So I have an object graph like so
RootElement
- name (String)
- adjective (String)
- items ArrayOfItems
- getItems (List<Item>)
- get(i) (Item)
Item
- name (String)
- value (double)
- alias (String)
- references ArrayOfReferences
- getReferences (List<Reference>)
- get(i) (Reference)
Reference
- prop1 (String)
- prop2 (Integer)
- prop3 (String)
There is a get and set pair for every property of every class represented in this object graph. Ideally every field of type String would end up trimmed, including enumerating any child objects contained in collections. There are no cycles contained within the object graph.
Is there any java library that implements some sort of generic object graph visitor pattern or String\Reflection utility library that does this?
An external third party library that does this would also be fine, it does not have to be part of the standard java libraries.
No, there's no built-in traversal for something like this, and remember that Java Strings are immutable, so you can't actually trim in place--you have to trim and replace. Some objects may not permit modification of their String variables.
Below is the explanation of solution that I have built using Java Reflection API. I have posted the working code (with its url to github) below. This solution mainly uses:
Java Reflection API
Independent handling of Java Collections
Recursion
To start with, I have used Introspector to go over the readMethods of the Class omitting the methods defined for Object
for (PropertyDescriptor propertyDescriptor : Introspector
.getBeanInfo(c, Object.class).getPropertyDescriptors()) {
Method method = propertyDescriptor.getReadMethod();
Cases
If the current level of Property is of type String
If its an Object Array of Properties
If its a String array
If its a type of Java Collection class
Separate placement for Map with special conditions to process its keys and values
This utility uses the Java Reflection API to traverse through an object graph with disciplined syntax of getters and setters and trims all strings encountered within an Object graph recursively.
Code
This entire util class with the main test class (and custom data types/pojos) is here on my github
Usage:
myObj = (MyObject) SpaceUtil.trimReflective(myObj);
Util method:
public static Object trimReflective(Object object) throws Exception {
if (object == null)
return null;
Class<? extends Object> c = object.getClass();
try {
// Introspector usage to pick the getters conveniently thereby
// excluding the Object getters
for (PropertyDescriptor propertyDescriptor : Introspector
.getBeanInfo(c, Object.class).getPropertyDescriptors()) {
Method method = propertyDescriptor.getReadMethod();
String name = method.getName();
// If the current level of Property is of type String
if (method.getReturnType().equals(String.class)) {
String property = (String) method.invoke(object);
if (property != null) {
Method setter = c.getMethod("set" + name.substring(3),
new Class<?>[] { String.class });
if (setter != null)
// Setter to trim and set the trimmed String value
setter.invoke(object, property.trim());
}
}
// If an Object Array of Properties - added additional check to
// avoid getBytes returning a byte[] and process
if (method.getReturnType().isArray()
&& !method.getReturnType().isPrimitive()
&& !method.getReturnType().equals(String[].class)
&& !method.getReturnType().equals(byte[].class)) {
System.out.println(method.getReturnType());
// Type check for primitive arrays (would fail typecasting
// in case of int[], char[] etc)
if (method.invoke(object) instanceof Object[]) {
Object[] objectArray = (Object[]) method.invoke(object);
if (objectArray != null) {
for (Object obj : (Object[]) objectArray) {
// Recursively revisit with the current property
trimReflective(obj);
}
}
}
}
// If a String array
if (method.getReturnType().equals(String[].class)) {
String[] propertyArray = (String[]) method.invoke(object);
if (propertyArray != null) {
Method setter = c.getMethod("set" + name.substring(3),
new Class<?>[] { String[].class });
if (setter != null) {
String[] modifiedArray = new String[propertyArray.length];
for (int i = 0; i < propertyArray.length; i++)
if (propertyArray[i] != null)
modifiedArray[i] = propertyArray[i].trim();
// Explicit wrapping
setter.invoke(object,
new Object[] { modifiedArray });
}
}
}
// Collections start
if (Collection.class.isAssignableFrom(method.getReturnType())) {
Collection collectionProperty = (Collection) method
.invoke(object);
if (collectionProperty != null) {
for (int index = 0; index < collectionProperty.size(); index++) {
if (collectionProperty.toArray()[index] instanceof String) {
String element = (String) collectionProperty
.toArray()[index];
if (element != null) {
// Check if List was created with
// Arrays.asList (non-resizable Array)
if (collectionProperty instanceof List) {
((List) collectionProperty).set(index,
element.trim());
} else {
collectionProperty.remove(element);
collectionProperty.add(element.trim());
}
}
} else {
// Recursively revisit with the current property
trimReflective(collectionProperty.toArray()[index]);
}
}
}
}
// Separate placement for Map with special conditions to process
// keys and values
if (method.getReturnType().equals(Map.class)) {
Map mapProperty = (Map) method.invoke(object);
if (mapProperty != null) {
// Keys
for (int index = 0; index < mapProperty.keySet().size(); index++) {
if (mapProperty.keySet().toArray()[index] instanceof String) {
String element = (String) mapProperty.keySet()
.toArray()[index];
if (element != null) {
mapProperty.put(element.trim(),
mapProperty.get(element));
mapProperty.remove(element);
}
} else {
// Recursively revisit with the current property
trimReflective(mapProperty.get(index));
}
}
// Values
for (Map.Entry entry : (Set<Map.Entry>) mapProperty
.entrySet()) {
if (entry.getValue() instanceof String) {
String element = (String) entry.getValue();
if (element != null) {
entry.setValue(element.trim());
}
} else {
// Recursively revisit with the current property
trimReflective(entry.getValue());
}
}
}
} else {// Catch a custom data type as property and send through
// recursion
Object property = (Object) method.invoke(object);
if (property != null) {
trimReflective(property);
}
}
}
} catch (Exception e) {
throw new Exception("Strings cannot be trimmed because: ", e);
}
return object;
}
Test
I also have a test class in there which creates a relatively complex object. The test class has different scenarios that cover:
String properties
Properties as custom datatypes which in turn have String properties
Properties as custom datatypes which in turn have properties as custom datatypes which in turn have String properties
List of custom data types
Set of Strings
Array of custom data types
Array of Strings
Map of String and custom data type
Object Graph:
Test Object Code Snippet:
public static Music buildObj() {
Song song1 = new Song();
Song song2 = new Song();
Song song3 = new Song();
Artist artist1 = new Artist();
Artist artist2 = new Artist();
song1.setGenre("ROCK ");
song1.setSonnet("X ");
song1.setNotes("Y ");
song1.setCompostions(Arrays.asList(new String[] { "SOME X DATA ",
"SOME OTHER DATA X ", "SOME MORE DATA X ", " " }));
Set<String> instruments = new HashSet<String>();
instruments.add(" GUITAR ");
instruments.add(" SITAR ");
instruments.add(" DRUMS ");
instruments.add(" BASS ");
song1.setInstruments(instruments);
song2.setGenre("METAL ");
song2.setSonnet("A ");
song2.setNotes("B ");
song2.setCompostions(Arrays.asList(new String[] { "SOME Y DATA ",
" SOME OTHER DATA Y ",
" SOME MORE DATA Y ", " " }));
song3.setGenre("POP ");
song3.setSonnet("DONT ");
song3.setNotes("KNOW ");
song3.setCompostions(Arrays.asList(new String[] { "SOME Z DATA ",
" SOME OTHER DATA Z ",
" SOME MORE DATA Z ", " " }));
artist1.setSongList(Arrays.asList(new Song[] { song1, song3 }));
artist2.setSongList(Arrays.asList(new Song[] { song1, song2, song3 }));
Map<String, Person> artistMap = new HashMap<String, Person>();
Person tutor1 = new Person();
tutor1.setName("JOHN JACKSON DOE ");
artistMap.put(" Name ", tutor1);
Person coach1 = new Person();
coach1.setName("CARTER ");
artistMap.put("Coach ", coach1);
artist2.setTutor(artistMap);
music.setSongs(Arrays.asList(new Song[] { song1, song2, song3 }));
music.setArtists(Arrays.asList(new Artist[] { artist1, artist2 }));
music.setLanguages(new String[] { " ENGLISH ", "FRENCH ",
"HINDI " });
Person singer1 = new Person();
singer1.setName("DAVID ");
Person singer2 = new Person();
singer2.setName("JACOB ");
music.setSingers(new Person[] { singer1, singer2 });
Human man = new Human();
Person p = new Person();
p.setName(" JACK'S RAGING BULL ");
SomeGuy m = new SomeGuy();
m.setPerson(p);
man.setMan(m);
music.setHuman(man);
return music;
}
Outcome:
#######BEFORE#######
>>[>>DAVID ---<<, >>JACOB ---<<]---[ ENGLISH , FRENCH , HINDI ]---[>>ROCK ---X ---Y ---[SOME X DATA , SOME OTHER DATA X , SOME MORE DATA X , ]---[ SITAR , GUITAR , BASS , DRUMS ]<<, >>METAL ---A ---B ---[SOME Y DATA , SOME OTHER DATA Y , SOME MORE DATA Y , ]---<<, >>POP ---DONT ---KNOW ---[SOME Z DATA , SOME OTHER DATA Z , SOME MORE DATA Z , ]---<<]---[>>---[>>ROCK ---X ---Y ---[SOME X DATA , SOME OTHER DATA X , SOME MORE DATA X , ]---[ SITAR , GUITAR , BASS , DRUMS ]<<, >>POP ---DONT ---KNOW ---[SOME Z DATA , SOME OTHER DATA Z , SOME MORE DATA Z , ]---<<]<<, >>{Coach =>>CARTER ---<<, Name =>>JOHN JACKSON DOE ---<<}---[>>ROCK ---X ---Y ---[SOME X DATA , SOME OTHER DATA X , SOME MORE DATA X , ]---[ SITAR , GUITAR , BASS , DRUMS ]<<, >>METAL ---A ---B ---[SOME Y DATA , SOME OTHER DATA Y , SOME MORE DATA Y , ]---<<, >>POP ---DONT ---KNOW ---[SOME Z DATA , SOME OTHER DATA Z , SOME MORE DATA Z , ]---<<]<<]---=> JACK'S RAGING BULL <=<<
Number of spaces : 644
#######AFTER#######
>>[>>DAVID---<<, >>JACOB---<<]---[ENGLISH, FRENCH, HINDI]---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>METAL---A---B---[SOME Y DATA, SOME OTHER DATA Y, SOME MORE DATA Y, ]---<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]---[>>---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]<<, >>{Name=>>JOHN JACKSON DOE---<<, Coach=>>CARTER---<<}---[>>ROCK---X---Y---[SOME X DATA, SOME OTHER DATA X, SOME MORE DATA X, ]---[GUITAR, SITAR, DRUMS, BASS]<<, >>METAL---A---B---[SOME Y DATA, SOME OTHER DATA Y, SOME MORE DATA Y, ]---<<, >>POP---DONT---KNOW---[SOME Z DATA, SOME OTHER DATA Z, SOME MORE DATA Z, ]---<<]<<]---=>JACK'S RAGING BULL<=<<
Number of spaces : 111
There is a non-zero count of the number of spaces in the above trimmed output because I didn't make an effort to override toString of any collections (List, Set) or Map. There are certain improvements to the code I want to make but for your case the solution should work just fine.
Limitations (further improvements)
Cannot handle undisciplined syntax of properties (invalid getters/setters)
Cannot handle chained Collections: for example, List<List<Person>> - because of the exclusive support to disciplined getters/setters convention
No Guava collection library support
Building off #SwissArmyKnife I converted his simple String trimming function into an interface with a default method. So any object where you would like to use object.trim(), you just have to add "implements Trimmable".
Simple String trim interface: Trimmable.class
/**
* Utility interface that trims all String fields of the implementing class.
*/
public interface Trimmable {
/**
* Trim all Strings
*/
default void trim(){
for (Field field : this.getClass().getDeclaredFields()) {
try {
field.setAccessible(true);
Object value = field.get(this);
if (value != null){
if (value instanceof String){
String trimmed = (String) value;
field.set(this, trimmed.trim());
}
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
An object that we would like to be trimmable: Person.class (implements Trimmable interface)
public class Person implements Trimmable {
private String firstName;
private String lastName;
private int age;
// getters/setters omitted
}
Now you can use person.trim()
Person person = new Person();
person.setFirstName(" John ");
person.setLastName(" Doe");
person.setAge(30);
person.trim();
I made a simple method for trimming String values with Reflection API.
public Object trimStringValues(Object model){
for(Field field : model.getClass().getDeclaredFields()){
try{
field.setAccessible(true);
Object value = field.get(model);
String fieldName = field.getName();
if(value != null){
if(value instanceof String){
String trimmed = (String) value;
field.set(model, trimmed.trim());
}
}
}catch(Exception e){
e.printStackTrace();
}
}
}
I haven't bumped in to any problems with this one yet. I know its an old thread, but it might help somone whos is looking for something simple.

Reflection IllegalArgumentException

I need to get private fields from one class and set them to another class.
This code works perfectly well for test Integer fields (100500 value gets written):
//get objects, class firs...
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, new Integer(100500));
}
Nontheless, when I switch to undefined type (the fields are of DIFFERENT types: Dates, Integers, Strings...
Eg class one has Date and class two has Date, I need to copy one value from another, but next field is going to be String in both classes)
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, field1);
}
I receive an IllegalArgumentException, e.g. I am not really able to get the values from one class and set it into another.
Please, dear community, give me a hint - what am I doing wrong?
to me, it looks like you hand over the field-reference instead of the field-value:
for(int i =0; i<fields1.length; i++) {
Field field1 = fields1 [i];
Field field = fields [i];
field.setAccessible(true);
field.set(app, field1.get(app1)); //or whatever object field1 is from
}
though i would not do it that way because order is a fragile thing...
you could use beanutils to copy your beans, if it is, what you want to achieve
This should suit your needs:
public static <T> void copyDeclaredFields(T from, T to) throws Exception {
Class<?> clazz = from.getClass();
if (!clazz.equals(to.getClass())) {
throw new IllegalArgumentException();
}
for (Field field : clazz.getDeclaredFields()) {
Object value = field.get(from);
field.set(to, value);
}
}
To call:
Item item1 = new Item();
// item1.set...
Item item2 = new Item();
copyDeclaredFields(item1, item2);
Your error seems to be related to the fact that you are trying to set Field1 as parameter of Field, instead of the value of Field1.
field.set(app, field1);
should instead be
field.set(app, field1.get(app1));
Take a look at a small working example;
If you change
fieldDest.set(destination, fieldSrc.get(source));
to
fieldDest.set(destination, fieldSrc);
you will get the same error of this question.
Hope that helps.
Code of the example:
import java.util.*;
import java.lang.*;
import java.lang.reflect.*;
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
Source source = new Source();
Destination destination = new Destination();
Class sourceClassObject = source.getClass();
Class destClassObject = destination.getClass();
Field[] sourceFields = sourceClassObject.getDeclaredFields();
Field[] destFields = destClassObject.getDeclaredFields();
for (Field fieldSrc : sourceFields) {
int mod = fieldSrc.getModifiers(); // get modifiers
System.out.print("Source Field: " + Modifier.toString(mod) + " "
+ fieldSrc.getType() + " " + fieldSrc.getName());
fieldSrc.setAccessible(true);
System.out.println(" [" + fieldSrc.get(source) + "]");
for (Field fieldDest : destFields){
if (fieldDest.getType().equals(fieldSrc.getType()) &&
fieldDest.getName().equals(fieldSrc.getName())){
fieldDest.setAccessible(true);
fieldDest.set(destination, fieldSrc.get(source));
}
}
}
destination.printValues();
}
static class Source{
public Source(){
strField = "This is a String";
intField = 42;
dateField = new Date();
}
private String strField;
private Integer intField;
private Date dateField;
}
static class Destination{
private String strField;
private Integer intField;
private Date dateField;
public void printValues(){
System.out.println("Destination Field values: ");
System.out.println("strField: " + strField);
System.out.println("intField: " + intField);
System.out.println("dateField: " + dateField);
}
}
}

How to get the current string from "Class.forName(name).newInstance()" using java

this is my code :
public static List populate(ResultSet rs, Class clazz) throws Exception {
ResultSetMetaData metaData = rs.getMetaData();
int colCount = metaData.getColumnCount();
List ret = new ArrayList();
Field[] fields = clazz.getDeclaredFields();
while (rs.next()) {
Object newInstance = clazz.newInstance();
for (int i = 1; i <= colCount; i++) {
try {
Object value = rs.getObject(i);
for (int j = 0; j < fields.length; j++) {
Field f = fields[j];
if (f.getName().replaceAll("_", "").equalsIgnoreCase(
metaData.getColumnName(i).replaceAll("_", ""))) {
BeanUtils.copyProperty(newInstance, f.getName(),
value);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
ret.add(newInstance);
}
rs.close();
return ret;
}
and this is the method to call it :
public List getLastAddress(String terminal_id, String last_2) throws Exception {
String sql ="SELECT a.adress_reality from accounts_location_"+last_2+" AS a WHERE a.terminal_id = '"
+terminal_id+"' ORDER BY a.time_stamp DESC limit 1";
System.out.println(sql);
ResultSet rs = getDr().getSt().executeQuery(sql);
return populate(rs, Class.forName("hdt.ChineseAddressBean"));
and then :
List cn_address=sd.getLastAddress(toNomber,last_2);
System.out.println(cn_address.get(0));
but it show :
hdt.ChineseAddressBean#f0eed6
so How to get the current string from cn_address.get(0),
thanks
this is my ChineseAddressBean.java:
package hdt;
public class ChineseAddressBean {
String adress_reality = "";
public String getAdress_reality() {
return adress_reality;
}
public void setAdress_reality(String adress_reality) {
this.adress_reality = adress_reality;
}
}
updated1:
when i use this , it show error :
updated2:
this is the error :
Object address = cn_address.get(0);
ChineseAddressBean chineseaddressbean = (ChineseAddressBean)address;
System.out.println(chineseaddressbean.getAdress_reality());
The above lines is what you need to do to achieve what you want.Please let me know if its working.
Meybe you need to make method toString () in Your class instance.
Apparently you are getting a list of objects of class "ChineseAddressBean" in cn_address. Right?
Then if you do
List cn_address=sd.getLastAddress(toNomber,last_2);
System.out.println(cn_address.get(0));
It will take the first element in the list and print it. To print it, it will try to convert it to String by calling toString method of the object. So if you override toString method in class "ChineseAddressBean" and return whatever you want to print, it will do the trick
you dont have a toString() method in your bean.
public String toString() {
return adress_reality;
}
Missed in your example that you need to cast the objects retrieved from your list to the appropriate type.
So:
System.out.println((ChineseAddressBean)cn_address.get(0));
Returning List you access Object (not ChineseAddressBean). Also when you print it you call default toString() method which returns class name followed by hash code.
You have to return List<ChineseAddressBean> or cast the result to ChineseAddressBean (which you are doing wrong).
Try this one:
System.out.println(((ChineseAddressBean)(cn_address.get(0))).getAdress_reality());
You can also write toString() method for ChineseAddressBean which returns address string and then you dont have to call getAdress_reality().
cn_address.get(0) returns an object, you should convert it to a string

Creating classes dynamically with Java

I have tried to find information about this but have come up empty handed:
I gather it is possible to create a class dynamically in Java using reflection or proxies but I can't find out how. I'm implementing a simple database framework where I create the SQL queries using reflection. The method gets the object with the database fields as a parameter and creates the query based on that. But it would be very useful if I could also create the object itself dynamically so I wouldn't have the need to have a simple data wrapper object for each table.
The dynamic classes would only need simple fields (String, Integer, Double), e.g.
public class Data {
public Integer id;
public String name;
}
Is this possible and how would I do this?
EDIT: This is how I would use this:
/** Creates an SQL query for updating a row's values in the database.
*
* #param entity Table name.
* #param toUpdate Fields and values to update. All of the fields will be
* updated, so each field must have a meaningful value!
* #param idFields Fields used to identify the row(s).
* #param ids Id values for id fields. Values must be in the same order as
* the fields.
* #return
*/
#Override
public String updateItem(String entity, Object toUpdate, String[] idFields,
String[] ids) {
StringBuilder sb = new StringBuilder();
sb.append("UPDATE ");
sb.append(entity);
sb.append("SET ");
for (Field f: toUpdate.getClass().getDeclaredFields()) {
String fieldName = f.getName();
String value = new String();
sb.append(fieldName);
sb.append("=");
sb.append(formatValue(f));
sb.append(",");
}
/* Remove last comma */
sb.deleteCharAt(sb.toString().length()-1);
/* Add where clause */
sb.append(createWhereClause(idFields, ids));
return sb.toString();
}
/** Formats a value for an sql query.
*
* This function assumes that the field type is equivalent to the field
* in the database. In practice this means that this field support two
* types of fields: string (varchar) and numeric.
*
* A string type field will be escaped with single parenthesis (') because
* SQL databases expect that. Numbers are returned as-is.
*
* If the field is null, a string containing "NULL" is returned instead.
*
* #param f The field where the value is.
* #return Formatted value.
*/
String formatValue(Field f) {
String retval = null;
String type = f.getClass().getName();
if (type.equals("String")) {
try {
String value = (String)f.get(f);
if (value != null) {
retval = "'" + value + "'";
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
} else if (type.equals("Integer")) {
try {
Integer value = (Integer)f.get(f);
if (value != null) {
retval = String.valueOf(value);
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
} else {
try {
String value = (String) f.get(f);
if (value != null) {
retval = value;
} else {
retval = "NULL";
}
} catch (Exception e) {
System.err.println("No such field: " + e.getMessage());
}
}
return retval;
}
There are many different ways to achieve this (e.g proxies, ASM), but the simplest approach, one that you can start with when prototyping is:
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
public class MakeTodayClass {
Date today = new Date();
String todayMillis = Long.toString(today.getTime());
String todayClass = "z_" + todayMillis;
String todaySource = todayClass + ".java";
public static void main (String args[]){
MakeTodayClass mtc = new MakeTodayClass();
mtc.createIt();
if (mtc.compileIt()) {
System.out.println("Running " + mtc.todayClass + ":\n\n");
mtc.runIt();
}
else
System.out.println(mtc.todaySource + " is bad.");
}
public void createIt() {
try {
FileWriter aWriter = new FileWriter(todaySource, true);
aWriter.write("public class "+ todayClass + "{");
aWriter.write(" public void doit() {");
aWriter.write(" System.out.println(\""+todayMillis+"\");");
aWriter.write(" }}\n");
aWriter.flush();
aWriter.close();
}
catch(Exception e){
e.printStackTrace();
}
}
public boolean compileIt() {
String [] source = { new String(todaySource)};
ByteArrayOutputStream baos= new ByteArrayOutputStream();
new sun.tools.javac.Main(baos,source[0]).compile(source);
// if using JDK >= 1.3 then use
// public static int com.sun.tools.javac.Main.compile(source);
return (baos.toString().indexOf("error")==-1);
}
public void runIt() {
try {
Class params[] = {};
Object paramsObj[] = {};
Class thisClass = Class.forName(todayClass);
Object iClass = thisClass.newInstance();
Method thisMethod = thisClass.getDeclaredMethod("doit", params);
thisMethod.invoke(iClass, paramsObj);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
It is possible to generate classes (via cglib, asm, javassist, bcel), but you shouldn't do it that way. Why?
the code that's using the library should expect type Object and get all the fields using reflection - not a good idea
java is statically typed language, and you want to introduce dynamic typing - it's not the place.
If you simply want the data in an undefined format, then you can return it in an array, like Object[], or Map<String, Object> if you want them named, and get it from there - it will save you much trouble with unneeded class generation for the only purpose of containing some data that will be obtained by reflection.
What you can do instead is have predefined classes that will hold the data, and pass them as arguments to querying methods. For example:
public <T> T executeQuery(Class<T> expectedResultClass,
String someArg, Object.. otherArgs) {..}
Thus you can use reflection on the passed expectedResultClass to create a new object of that type and populate it with the result of the query.
That said, I think you could use something existing, like an ORM framework (Hibernate, EclipseLink), spring's JdbcTemplate, etc.
This is possible, but (I believe) you need something like ASM or BCEL.
Alternately, you could use something with more power (like Groovy).
It will take a couple of minutes to create a data model class for each table, which you can easily map to the database with an ORM like Hibernate or by writing your own JDBC DAOs. It is far easier than delving deeply into reflection.
You could create a utility that interrogates the database structure for a table, and creates the data model class and DAO for you. Alternatively you could create the model in Java and create a utility to create the database schema and DAO from that (using reflection and Java 5 Annotations to assist). Don't forget that javaFieldNames are different from database_column_names typically.
Recently I needed to create about 200 simple classes from medatata (objects filled with static data) and I did it through the open source burningwave library, with the following scenario:
The classes needed to have a certain prefix in the name, for example "Registro "*.java;
The classes needed to extend from a superclass Registro.java
The classes needed to contain JPA annotations like #Entity, #Column (in attributes), Lombok annotations and custom annotations.
Here is the link to the repository with the complete project: https://github.com/leandrosoares6/criacao-classes-entidade-efd
Here is the code snippet responsible for creating the classes:
public class RegistrosClassFactory {
private static final String PACOTE = "com.example.demo.model.registros";
private static final String SCHEMA = "MY_SCHEMA";
private static final String PREFIXO = "Registro";
static void criaRegistros() {
List<RegistroTest> registros = RegistroMetadataFactory.criaMetadados();
criaClasses(registros);
}
private static void criaClasses(List<RegistroTest> registros) {
for (RegistroTest registroTest : registros) {
UnitSourceGenerator gerador = UnitSourceGenerator.create(PACOTE);
ClassSourceGenerator registro = ClassSourceGenerator
.create(TypeDeclarationSourceGenerator.create(PREFIXO + registroTest.getNome()))
.addModifier(Modifier.PUBLIC)
.addAnnotation(AnnotationSourceGenerator.create(Getter.class))
.addAnnotation(AnnotationSourceGenerator.create(Setter.class))
.addAnnotation(AnnotationSourceGenerator.create(NoArgsConstructor.class))
.addAnnotation(AnnotationSourceGenerator.create(ToString.class))
.addAnnotation(AnnotationSourceGenerator.create(Entity.class))
.addAnnotation(AnnotationSourceGenerator.create(Table.class)
.addParameter("name",
VariableSourceGenerator.create(String.format("\"%s\"",
registroTest.getNomeTabelaBd())))
.addParameter("schema", VariableSourceGenerator
.create(String.format("\"%s\"", SCHEMA))));
criaColunas(registroTest.getCampos(), registro);
registro.addConstructor(FunctionSourceGenerator.create().addModifier(Modifier.PUBLIC)
.addParameter(VariableSourceGenerator.create(String.class, "linha"))
.addBodyCodeLine("super(linha);")).expands(Registro.class);
gerador.addClass(registro);
// System.out.println("\nRegistro gerado:\n" + gerador.make());
String caminhoPastaRegistros = System.getProperty("user.dir") + "/src/main/java/";
gerador.storeToClassPath(caminhoPastaRegistros);
}
}
private static void criaColunas(List<Campo> campos, ClassSourceGenerator registro) {
for (Campo campo : campos) {
VariableSourceGenerator field = VariableSourceGenerator
.create(TypeDeclarationSourceGenerator.create(String.class),
campo.getNomeAtributo())
.addModifier(Modifier.PRIVATE)
.addAnnotation(AnnotationSourceGenerator.create(Column.class)
.addParameter("name", VariableSourceGenerator
.create(String.format("\"%s\"", campo.getNome())))
)
.addAnnotation(AnnotationSourceGenerator.create(Indice.class).addParameter(
"valor",
VariableSourceGenerator.create(String.valueOf(campo.getSequencial()))));
if (campo.getNome().equals("ID")) {
field.addAnnotation(AnnotationSourceGenerator.create(Id.class));
}
if (campo.getEId()) {
field.addAnnotation(AnnotationSourceGenerator.create(CampoTipoId.class));
}
if (campo.getEData()) {
field.addAnnotation(AnnotationSourceGenerator.create(CampoTipoData.class));
}
if (campo.getEDataPart()) {
field.addAnnotation(AnnotationSourceGenerator.create(CampoTipoDataPart.class));
}
registro.addField(field);
}
}
}
I'm aware of the performance drawback of reflection but for my little project I needed this and I created a project lib which converts JSON to Java and then finally .class in JVM context.
Anyone need such thing can have a look into my open source solution, which requires JDK to compile the code.
https://medium.com/#davutgrbz/the-need-history-c91c9d38ec9?sk=f076487e78a1ff5a66ef8eb1aa88f930

Categories

Resources