I have an instance of class android.icu.util.TimeZone which actually instance of android.icu.impl.OlsonTimeZone. I need to retrieve a field of transitions using reflection. But getDeclaredFields retrieves only one static field. How could it be, if during debuging I see lots of fields in this class?
TimeZone tz = TimeZone.getTimeZone("Europe/Kiev");
try {
Class<?> actionClass = Class.forName(tz.getClass().getName()/*, true, ClassLoader.getSystemClassLoader()*/); // Also have tried with SystemClassLoader
Field[] allFields = actionClass.getDeclaredFields();
for (Field field : allFields) {
Log.d("field:", field.getName());
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
When I try to retrieve transitionTimes64 directly I'v got NoSuchFieldException No field transitionTimes in class Landroid/icu/impl/OlsonTimeZone; (declaration of 'android.icu.impl.OlsonTimeZone' appears in /apex/com.android.runtime/javalib/core-libart.jar
Related
How can I iterate over the attributes of an object, with the attribute names provided in a list/array - NOT all attributes, like using reflection & getDeclaredFields().
public class MyClass
{
public type1 att1;
public type2 att2;
public type3 att3;
public MyClass(
att1="helo";
att2="bye";
att3="morning";
);
...
public void function()
{
String myStrings[];
myStrings = new String[] { "att2", "att3" };
MyClass myobject = new MyClass();
for(var in myStrings)
{
System.out.println(var);
System.out.println(myobject.var);
System.out.println();
}
}
}
Your question is somewhat ambiguous about using reflection. If you are OK with reflection, but want specific fields only without iterating over getDeclaredFields(), then the following code should work for you:
for (String var : myStrings) {
Field field = MyClass.class.getDeclaredField(var);
field.setAccessible(true);
System.out.println(var);
System.out.println(field.get(myObject));
System.out.println();
}
Note that this code works for private fields, too. Also, keep in mind that you'll have to handle exception associated with the reflection calls.
UPDATE: Exceptions thrown in this code.
MyClass.class.getDeclaredField(var) declares a checked NoSuchFieldException. You must handle it because obviously there is no mechanism to make sure that the fields in myString match an actual implementation of MyClass.
field.get(myObject) throws a checked IllegalAccessException if the field is inaccessible. Which it should not be because of field.setAccessible(true), but you still have to catch or re-throw the exception.
There are also unchecked exceptions you may want to handle. See the javadoc for details
java.lang.Class.getDeclaredField(String)
java.lang.reflect.AccessibleObject.setAccessible(boolean) inherited by java.lang.reflect.Field
java.lang.reflect.Field.get(Object)
You probably want to use some technology that builds on top of JavaBeans / BeanInfo. Apache Commons / BeanUtils is a good starting point here.
Please refer to this previous answer of mine for more info:
https://stackoverflow.com/a/5856982/342852
But if you just want to use fields, not bean properties, here's a Java 8 method to do so:
public static Map<String, Object> getFieldProperties(Object o, Collection<String> fields) {
Class<?> type = o.getClass();
return fields.stream().map(n -> {
try {
return type.getDeclaredField(n);
} catch (NoSuchFieldException e) {
throw new IllegalStateException(e);
}
}).collect(Collectors
.toMap(
(Function<Field, String>) Field::getName,
(Function<Field, Object>) field -> {
try {
field.setAccessible(true);
return field.get(o);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}));
}
Unfortunately the checked exceptions make this more verbose than it would need to be.
this is my situation:
I have a method which has a String as parameter. This method has to receive an object from a class called Urls. The object it has to recieve, has the same name as the value of the String. Here is my code:
private Object getObject(String objectName){
try
{
Field field = Urls.class.getField(objectName);
}
catch (NoSuchFieldException e)
{}
catch (IllegalAccessException e)
{}
}
And here is my Urls class:
public class Urls{
public static final String[] ASTUN = new String[]{
"http://www.astun.com/camara/truchas.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=astun/astun.jpg",
"http://www.astun.com/camara/caba%C3%B1a%20sarrios.jpg",
"http://www.astun.com/camara/sector%20sarrios.jpg",
"http://www.astun.com/camara/sector%20raca%20prad.jpg",
"http://www.astun.com/camara/sector%20aguila%20cr.jpg",
"http://www.astun.com/camara/sector%20truchas.jpg",
"http://www.astun.com/camara/sector%20llanos%20.jpg",
"http://www.astun.com/camara/llegada.jpg",
"http://www.astun.com/camara/terraza.jpg",
"http://www.astun.com/camara/panoramica.jpg",
"http://www.astun.com/camara/snow.jpg"
};
private static final String[] CANDANCHU = new String[]{
"https://www.todonieve.com/photowebcam.asp?fotografia=candanchu/candanchu.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=CandanchuNew/CandanchuNew.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=candanchu_rinconada/candanchu_rinco.jpg",
"https://www.todonieve.com/photowebcam.asp?fotografia=candanchu_tobazo/candanchu_tobazo.jpg"
};
}
So, that way I have a Field object, but how can I get the String[] of that field? I have read about the get(Object object) method of Field class but it seems that i doesnt do what I want to do...
EDIT: I WANT TO GET ASTUN OR CANDACHU STRING ARRAYS
Avoid reflection whenever possible. It often does more harm than good.
Put them into a map:
public class Urls {
//put your arrays here
private static final Map<String,String[]> urlsLists = new HashMap<>();
static {
urlLists.put("ASTUN", ASTUN);
urlLists.put("CANDANCHU", CANDANCHU);
}
public static String[] getUrlList(String name) {
return urlLists.get(name);
}
}
And then call it like this:
private Object getObject(String objectName){
return Urls.getUrlList(objectName);
}
Update
You loose a lot of nice stuff Java help you with, including type-safety, encapsulation and compile-time checks. Because of this it is a lot more error prone. There is a much increased risk of run-time errors and you need a bunch of extra code to handle this. Your brief example already have two catch clauses. Trust me - that will just get worse.
You can even improve type-safety more by creating an Enum to define url-types. Then you will get compile time checks that you have spelled the name right and even auto-completion all through-out your code. :)
public class Urls {
public enum UrlTypes {ASTUN; CANDANCHU;}
// ..
private static final Map<UrlTypes,String[]> urlsLists = new HashMap<>();
static {
urlLists.put(UrlTypes.ASTUN, ASTUN);
urlLists.put(UrlTypes.CANDANCHU, CANDANCHU);
}
..
public static String[] getUrlList(UrlTypes name) {
return urlLists.get(name);
}
}
Every error you can catch at compile-time instead of at run-time can save you between half an hour or half a week of work, when things get complex.
You will need something like this:
private Object getObject(String objectName){
try
{
Field field = Urls.class.getField(objectName);
Object o = field.get(null); // null works as well.
return o;
}
catch (NoSuchFieldException e)
{ e.printStackTrace(); }
catch (IllegalAccessException e)
{ e.printStackTrace(); }
}
private String[] getStringArray(String arrayName)
{
return (String[]) getObject(arrayName);
}
Usage:
Object o = getObject("ASTUN");
// or:
String[] arr = getStringArray("ASTUN");
getField will return the (reflexive) representation of the field concept in the Urls class. You then need to bind it with an actual object of that class to have access to the contents of the field in that object.
Field field = Urls.class.getFiled(objectName);
String[] values = (String[]) field.get(o);
where o is a variable of type Urls.
Note the cast to String[] as Field.get() will return an Object as it does not know the actual type. You should make sure that the type is indeed correct by using the Field.getType() method and compare that to Urls.class.
Since objects dont have names, you will need to create ypur own class, put the field variable in there, then use that instead of Object. Or use a Map for better key/value logging.
i create and set values like the following in java
public Class creatObjectWithDefaultValue(String className) throws IllegalArgumentException, IllegalAccessException {
DefaultParamValues defaultParamValues = null;
Class objectClass = null;
try {
objectClass = Class.forName(className);
Field[] fields = objectClass.getClass().getDeclaredFields();
for(Field f:fields){
if(!f.isAccessible()){
f.setAccessible(true);
Class<?> type = f.getType();
if(type.equals(Integer.class)){
f.set(objectClass, defaultParamValues.INTEGER);
} else if(type.equals(BigInteger.class)){
f.set(objectClass, defaultParamValues.BIGINTEGER);
}else if(type.equals(LocalDate.class)){
f.set(objectClass, defaultParamValues.DATE);
}else if(type.equals(Boolean.class)){
f.set(objectClass, defaultParamValues.BOOLEAN);
}else if(type.equals(Long.class)){
f.set(objectClass, defaultParamValues.LONGVALUE);
}
f.setAccessible(false);
}
//System.out.println(f.get(objectClass));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return objectClass;
}
now i want to convert the return object as JSON or JSON Array i tried some thing like this but it throws exception as The constructor JSONObject(Class) is undefined
System.out.println ( new JSONObject( te.creatObjectWithDefaultValue("com.hexgen.ro.request.CreateRequisitionRO") ).toString () );
Please help me to correct the mistake.
Best Regards
Why don't you use a Jackson for working with JSON data? Reinventing the wheel is most often error-prone and is only suitable for either education or the case when no library or framework fits your purposes at all.
Now, for JSON <-> Object conversion, there is not a single reason not to use a higher level framework, unless you're explicitly trying to investigate Reflection itself.
there is no constructor with the parameter class in JSONObject.
but you could create an object of the class and pass it to the jsonobject constructor:
System.out.println ( new JSONObject(te.creatObjectWithDefaultValue("com.hexgen.ro.request.CreateRequisitionRO").newInstance() ).toString () );
this only works with classes that have a parameterless constructor
This is very clear.
The constructor JSONObject(Class) is undefined
The API → http://www.json.org/javadoc/org/json/JSONObject.html
I have a series of classes, which are unrelated. Each classs has one property with and #PrimaryKey (with getter and setter) that could be of any type. How can I use reflection to find which property of an instance of any class has the #PrimaryKey annotation - so I can get its value as a string.
The code doesn't know which type of class its being passed - it will just be of type "Object"
You can do something like this:
for (Field field : YourClass.class.getDeclaredFields()) {
try {
Annotation annotation = field.getAnnotation(PrimaryKey.class);
// what you want to do with the field
} catch (NoSuchFieldException e) {
// ...
}
}
If you are working with the instance of your class then you can do this to get its class object:
Class<?> clazz = instance.getClass();
so the first line becomes something like this:
instance.getClass().getDeclaredFields()
If you are in trouble you can always check out the official documentation. I believe it is quite good.
You can get all fields of a class and then iterate and find which field has your annotation:
Field[] fields = YourClass.class.getDeclaredFields();
for (Field field : fields) {
Annotation annot = field.getAnnotation(PrimaryKey.class);
if (annot != null) {
System.out.println("Found! " + field);
}
}
First of all you need to find all classes that may have the annotation in their members. This can be accomplished using Spring Framework ClassUtils:
public static void traverse(String classSearchPattern, TypeFilter typeFilter) {
ClassLoader classLoader = ClassUtils.getDefaultClassLoader();
ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(classLoader);
Resource[] resources = null;
try {
resources = resourceResolver.getResources(classSearchPattern);
} catch (IOException e) {
throw new FindException(
"An I/O problem occurs when trying to resolve resources matching the pattern: "
+ classSearchPattern, e);
}
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
for (Resource resource : resources) {
try {
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
if (typeFilter.match(metadataReader, metadataReaderFactory)) {
String className = metadataReader.getClassMetadata().getClassName();
Class<?> annotatedClass = classLoader.loadClass(className);
// CHECK IF THE CLASS HAS PROPERLY ANNOTATED FIELDS AND
// DO SOMETHING WITH THE CLASS FOUND... E.G., PUT IT IN SOME REGISTRY
}
} catch (Exception e) {
throw new FindException("Failed to analyze annotation for resource: " + resource, e);
}
}
}
I'm using spring MVC for receiving a JSON from client and automatically create an object from it. The problem is that the client doesn't send to server all the fields that are in the entity, but some fields are null and overwrite existing values calling userDao.persist(user). For example, i have this entity:
#Entity
public class User {
#Id #GeneratedValue
private int id;
private String username;
private String password;
private String email;
But the user never send me the password, so the object built from JSON has "password" field empty. I don't want the password field to be overwritten by a null value. There's a way to say to hibernate "if you find a null value ignore it and don't overwrite the value that is saved in database?". I can't believe that there isn't a easy solution to this apparently simple problem.
I think the source of your problem is that the object you're getting back from your JSON parsing never had the actual values in it. It is a bean that has only the values set that are in your JSON.
You need to load your entity from the DB and then set the non-null fields from your JSON onto the loaded entity. That way only fields that are supplied in the JSON will be set.
I recommend an adapter of some sort to "merge" (not JPA merge) the DB version and the JSON version before saving the DB version.
Adding a #NotNull constraint and Bean Validation will make sure the values are not null when attempting to save. Unfortunately they won't help you get the values into the entity to save.
I have the same issue.
I solved it in this way.
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import java.lang.reflect.Field;
import java.util.Hashtable;
public class Updater {
private final static Logger log = LogManager.getLogger(Updater.class);
public static <E> E updater(E oldEntity, E newEntity) {
Field[] newEntityFields = newEntity.getClass().getDeclaredFields();
Hashtable newHT = fieldsToHT(newEntityFields, newEntity);
Class oldEntityClass = oldEntity.getClass();
Field[] oldEntityFields = oldEntityClass.getDeclaredFields();
for (Field field : oldEntityFields){
field.setAccessible(true);
Object o = newHT.get(field.getName());
if (o != null){
try {
Field f = oldEntityClass.getDeclaredField(field.getName());
f.setAccessible(true);
log.info("setting " + f.getName());
f.set(oldEntity, o);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
return oldEntity;
}
private static Hashtable<String, Object> fieldsToHT(Field[] fields, Object obj){
Hashtable<String,Object> hashtable = new Hashtable<>();
for (Field field: fields){
field.setAccessible(true);
try {
Object retrievedObject = field.get(obj);
if (retrievedObject != null){
log.info("scanning " + field.getName());
hashtable.put(field.getName(), field.get(obj));
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return hashtable;
}
}
It is clearly a workaround but it seems to work smoothly... in the next days I think I'll write the recursive part.
Implement setters for you attributes and do the checks there.
Check Hibernate Validation project, which can be used to verify your object on DAO level, as well as on Spring Web layer.
I wrote this answer while being an unexpirienced studen. Today my answer would be similar to the one from #James DW. Also, from the term userDao, I assume that it is some kind of ORM/ODM. In that case it is definitly worth searching "pros and cons of ORM/ODM".
original answer (which was accepted back in 2011):
If your problem is only the database, then I suggest you use a stored procedure, which checks if that value is null, and then dose not change the existing value. That way you can still send a null value, and your validation is on server side which is more robust.