I have an object (basically a VO) in Java and I don't know its type.
I need to get values which are not null in that object.
How can this be done?
You can use Class#getDeclaredFields() to get all declared fields of the class. You can use Field#get() to get the value.
In short:
Object someObject = getItSomehow();
for (Field field : someObject.getClass().getDeclaredFields()) {
field.setAccessible(true); // You might want to set modifier to public first.
Object value = field.get(someObject);
if (value != null) {
System.out.println(field.getName() + "=" + value);
}
}
To learn more about reflection, check the Oracle tutorial on the subject.
That said, if that VO is a fullworthy Javabean, then the fields do not necessarily represent real properties of a VO. You would rather like to determine the public methods starting with get or is and then invoke it to grab the real property values.
for (Method method : someObject.getClass().getDeclaredMethods()) {
if (Modifier.isPublic(method.getModifiers())
&& method.getParameterTypes().length == 0
&& method.getReturnType() != void.class
&& (method.getName().startsWith("get") || method.getName().startsWith("is"))
) {
Object value = method.invoke(someObject);
if (value != null) {
System.out.println(method.getName() + "=" + value);
}
}
}
That in turn said, there may be more elegant ways to solve your actual problem. If you elaborate a bit more about the functional requirement for which you think that this is the right solution, then we may be able to suggest the right solution. There are many, many tools available to massage javabeans. There's even a built-in one provided by Java SE in the java.beans package.
BeanInfo beanInfo = Introspector.getBeanInfo(someObject.getClass());
for (PropertyDescriptor property : beanInfo.getPropertyDescriptors()) {
Method getter = property.getReadMethod();
if (getter != null) {
Object value = getter.invoke(someObject);
if (value != null) {
System.out.println(property.getName() + "=" + value);
}
}
}
Here's a quick and dirty method that does what you want in a generic way. You'll need to add exception handling and you'll probably want to cache the BeanInfo types in a weakhashmap.
public Map<String, Object> getNonNullProperties(final Object thingy) {
final Map<String, Object> nonNullProperties = new TreeMap<String, Object>();
try {
final BeanInfo beanInfo = Introspector.getBeanInfo(thingy
.getClass());
for (final PropertyDescriptor descriptor : beanInfo
.getPropertyDescriptors()) {
try {
final Object propertyValue = descriptor.getReadMethod()
.invoke(thingy);
if (propertyValue != null) {
nonNullProperties.put(descriptor.getName(),
propertyValue);
}
} catch (final IllegalArgumentException e) {
// handle this please
} catch (final IllegalAccessException e) {
// and this also
} catch (final InvocationTargetException e) {
// and this, too
}
}
} catch (final IntrospectionException e) {
// do something sensible here
}
return nonNullProperties;
}
See these references:
BeanInfo (JavaDoc)
Introspector.getBeanInfo(class) (JavaDoc)
Introspection (Sun Java
Tutorial)
I've an object (basically a VO) in
Java and I don't know its type. I need to get values which are not null in that object.
Maybe you don't necessary need reflection for that -- here is a plain OO design that might solve your problem:
Add an interface Validation which expose a method validate which checks the fields and return whatever is appropriate.
Implement the interface and the method for all VO.
When you get a VO, even if it's concrete type is unknown, you can typecast it to Validation and check that easily.
I guess that you need the field that are null to display an error message in a generic way, so that should be enough. Let me know if this doesn't work for you for some reason.
Related
I have an object which I must validate values off the problem, some of the attributes of the Objects are arrays of custom objects. Such that it will involve some boring down into the individual elements of the array. Excuting the getters for each element such as:
AttribGrp[] x = Object.getAttribGrp()
x[i].getSomeValue()
It is this I need to get to. I have been extracted the data using an Enum with the list of
the attributes In the following manner.
public String getAttribValueAsString(MethodEnum attribName)
{
String attribValue = null;
Object value = getAttrib(attribName.toString());
if (value != null)
attribValue = value.toString();
return attribValue;
}
calling:
private Object invoke(String methodName, Object newValue)
{
Object value = null;
try
{
methodInvoker.setTargetMethod(methodName);
if (newValue != null)
methodInvoker.setArguments(new Object[]{newValue});
else
methodInvoker.setArguments(new Object[]{});
methodInvoker.prepare();
value = methodInvoker.invoke();
}
catch (ClassNotFoundException e)
{
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
}
catch (NoSuchMethodException e)
{
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
}
catch (InvocationTargetException e)
{
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
}
catch (IllegalAccessException e)
{
throw new IllegalStateException("Method invocation failed. " + e.getMessage(),e);
}
return value;
}
I will be working with a number of arrays of different types and of different values within the arrays. I want to create a method as follows.
public Object getAttribArray(RIORepeatingGrpEnum repeatingGrp)
{
repeatingGrp[] grp = null;
Object grpVal = getAttrib(repeatingGrp.toString());
if(grp != null)
grp = (repeatingGrp[]) grpVal;
return grp;
}
This is giving me multiple errors mainly concerned with repeatingGrp[]. The array type should be the same name as enum. Is it possible to create a method like this that will create an array of non defined type?
If you want to have arrays of unknown types, use generics:
public <T> T[] getAttribArray(Class<T> repeatingGrpClass)
{
//get the attribute based on the class (which you might get based on the enum for example)
return (T[]) getAttrib( repeatingGrpClass.getName() ); //note that you might want to use the class object instead of its name here
}
No, you cannot use a variable (repeatingGrp) as a type.
There are ways to do "dynamic" casting, but these wouldn't help you. The return type of getAttribArray is Object, which would defeat the point of casting to a particular type.
And even if you could fix that, it's still not clear what you could do with this mechanism. What do you want to be able to do with the result of getAttribArray()?
As Oli Charlesworth points out, you can not use the variable name to cast. For a generic type, you will have to cast to Object or Object[].
Also the Object -> Object[] cast looks illegal. You probably just want a straight cast like so:
public Object[] getAttribArray(RIORepeatingGrpEnum repeatingGrp)
{
Object[] grp = (Object[])getAttrib(repeatingGrp.toString());
return grp;
}
I'm trying to find an easy way to perform multiple null checks/ replacements in multiple variables in Java.
I have an object with about 20 String variables. In the constructor I want to check if any of the variable values are null. If they are null I want to replace them with an empty String. I could perform a series of if statements but I feel like there must be a cleaner way to do this.
Unless you want to resort to reflection (which I strongly discourage) your best bet is probably to create a helper method (return s == null ? "" : s) and do
field1 = nullToEmpty(field1);
field2 = nullToEmpty(field2);
...
If you already depend on Apache Commons or Guava you can use StringUtils.defaultString or Strings.nullToEmpty.
I agree with aioobe, using reflection is something you should avoid like the plague. But if you are blessed with a project where for example you have to mock a REST interface manually and the objects that come via this interface have tons of Integer, String, Double etc. inside I think you have no other choice.
Here is a generic method that replaces all null pointers it can find in an object with its scalar default values, fills String fields with an empty string and does so recursively if the objects it finds have a parameterless default constructor. Hope this helps other people in the same situation as well.
static void fillNullObjects(Object object) {
Field[] fields = object.getClass().getDeclaredFields();
for (Field field : fields) {
try {
field.setAccessible(true);
if (field.get(object) != null) {
continue;
}
else if (field.getType().equals(Integer.class)) {
field.set(object, 0);
}
else if (field.getType().equals(String.class)) {
field.set(object, "");
}
else if (field.getType().equals(Boolean.class)){
field.set(object, false);
}
else if (field.getType().equals(Character.class)) {
field.set(object, '\u0000');
}
else if (field.getType().equals(Byte.class)) {
field.set(object, (byte) 0);
}
else if (field.getType().equals(Float.class)) {
field.set(object, 0.0f);
}
else if (field.getType().equals(Double.class)) {
field.set(object, 0.0d);
}
else if (field.getType().equals(Short.class)) {
field.set(object, (short) 0);
}
else if (field.getType().equals(Long.class)) {
field.set(object, 0L);
}
else if (field.getType().getDeclaredFields().length > 0){
for (Constructor<?> constructor : field.getClass().getConstructors()) {
if (constructor.getParameterTypes().length == 0) {
field.set(object, constructor.newInstance());
fillNullObjects(field.get(object));
}
}
}
} catch (IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
}
}
Check out Apache Commons' StringUtils
StringUtils.defaultString(yourString)
This replaces nulls with an empty String. Or you can define your own replacement:
StringUtils.defaultString(null, "foo") // returns "foo"
http://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/StringUtils.html#defaultString(java.lang.String)
Store your variables in an array (or list, if you don't know exacty the number of variables but I don't think so) and loop over it
String[] variables;
//...
for(int i = 0; i < variables.length; i++)
if(variables[i] == null) variables[i] = "";
20 field variables sounds like an egregious case. You should try to avoid explicitly handling that many variables in any situation, or at least factor the code so they are only ever explicitly listed in one place.
A common pattern is to associate each variable with an enumeration, and use the enumeration as a key in a Map with type Enum -> String, or use the enumeration's ordinal as an index into a String array that is sized to the Enumeration value.
Like so:
public enum StringProperties {
TTL, RECVBUF, SENDBUF, RETRIES, ... ;
}
If you wanted explicit default values, you can couple an enumeration with a number of parameters:
public enum StringProperties {
TTL ("100"),
RECVBUF ("1024"),
SENDBUF ("1500"),
RETRIES ("10"),
...
;
public String getDefaultValue() { ... }
}
This strategy means that your code needs minimal modification if you need to add/remove a property, or change a default value.
In your (copy constructor?) case, you can loop over the enumeration values with something like:
for (StringProperties property : StringProperties.values()) {
if (obj.getProperty(property) != null) {
// handle present case
...
} else {
// handle default storage case
...
}
}
Or, like thomas said, you can use a String array on its own, but this assumes that you don't need a way to address each String.
public static String checkNull (String inputString){
if(inputString == null){
inputString = "";
}
return inputString;
}
And just call that whenever you want to check a string.
For each field use the standard Java method:
Objects.toString(field, "");
Avoid constructor with a large number of fields if possible. Use Builder instead (as suggested in Effective Java, Item 2: Consider a builder when faced with many constructor parameters).
I wonder if it would be possible to 'avoid' null checks in Java, take an example from this code:
#Override
public List<AccountBean> search(AccountConstraint... c) {
if (c.length == 0) {
throw new IllegalArgumentException("dao.AccountDAO.search: c.length == 0");
}
try {
List<AccountBean> beans = new ArrayList<>();
for (AccountConstraint ac : c) {
Builder builder = new QueryBuilder.Builder("SELECT * FROM accounts");
if (ac.getAccountId() != null) {
builder.clause("accountId >= " + ac.getAccountId().getMin() + " AND accountId <= " + ac.getAccountId().getMax());
}
if (ac.getUsername() != null) {
builder.clause("username = \"" + ac.getUsername() + "\"");
}
if (ac.getPassword() != null) {
builder.clause("password = \"" + ac.getPassword() + "\"");
}
if (ac.getEmail() != null) {
builder.clause("email = \"" + ac.getEmail() + "\"");
}
PreparedStatement ps = connection.prepareStatement(builder.build().getQuery());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
beans.add(new AccountBean(rs));
}
}
return beans;
} catch (SQLException ex) {
throw new RuntimeException(ex);
}
}
It has to check 4 times for the != null because else the code would fail.
Is it possible to turn the if (object != null) statements into one-liners that only execute if there is no NullPointerException? When there is an exception, the line should just be ignored.
I am not talking about a general language feature here, I am talking about a feature that would only be turned in when you explicitely decide to do so.
For example: NullCheck(builder.clause("username = \"" + ac.getUsername() + "\"")); would be a snippet of the suggested code.
Is something like that possible in Java?
Also if it is not possible, might it be possible in Java 8 to use methods (voids) directly in methods?
So then code like this could actually work?
public static NullCheck(Void void) {
try {
void.execute();
}
catch (NullPointerException e) {
//ignore
}
}
I know I could put the method inside it's own class that extends an interface that has method execute() and then pass that class around, but that would defeat the purpose of getting rid of the null checks or anything that would be even more complicated.
Regards.
WARNING: The way I used PreparedStatement here is prone to SQL Injection. Do not reuse this code.
You can avoid these checks by assuming that these methods do not return null values.
How can you assume this? By having the specification for the AccountConstraint say so. The code in AccountConstraint is then responsible for ensuring the values are not null, rather than your search method being responsible for handling null values. You might have to change the design of AccountConstraint to do this.
And what happens if your assumption is wrong? That is, if AccountConstraint is buggy. An exception will be thrown, which you were not expecting. But that is what can happen when you have a bug: an unexpected exception is thrown. Debugging the code will be easy, because the stacktrace will show you which method of AccountConstraint is returning an invalid null value.
Yes and No.
There are two approaches to tackle the null problem:
Special Operators like the Safe Navigation Operator in Groovy. If x.y throws a NullPointerException x?.yreturns just null. Since Java does not allow creation of new operators, you can't do this in Java. Operators like this where considered for JDK8 but where dropped. If you want have something like this, switch to Groovy or one of the many other languages having this feature.
Special Class many languages have a special interface for representing a value that might be null. In Scala it is called Option. Option has two implementations: None + Some. None replaces null. Whenever you want to do something with the value, you don't use it directly, but you call map on the Option with a function as an argument. If it is actually a None, nothing happens, you just get back None. If it is a Some, the function gets executed on the value and you get an Option with the result. That way you can work with Options all the time, without worrying about nulls.
Actually it is in now way special, so you can create such a class yourself with Java. The problem is only, that Java doesn't have functions, so you have to use anonymous classes. This makes the whole thing really cumbersome and only a theoretical option.
JDK8 has a Option class. As far as I know it is missing the map method which makes the whole thing a bad joke in my opinion. But since the most important tool (anonymous functions) are there will be a proper Option implementation provided by one of the usual suspects (Google, Apache ...)
As it stands, you could probably write a method like
public void clauseIfNotNull(Builder builder, String format, Object o) {
if (o != null) {
builder.clause(String.format(format, o));
}
}
and then that'd look like clauseIfNotNull(builder, "username = \"%s\"", ac.getUsername());
Other than that, there's not much you can do with Java 7.
Make a minimal adaptor object on the Builder
class NotNullClauseAdapter
{
private final Builder builder;
public NotNullClauseAdapter(Builder builder) {
this.builder = builder;
}
public void clause(String format, Object o) {
if (o != null) {
builder.clause(String.format(format, o));
}
}
}
Use this in your code:
for (AccountConstraint ac : c) {
Builder builder = new QueryBuilder.Builder("SELECT * FROM accounts");
NotNullClauseAdapter adapter = new NotNullClauseAdapter(builder);
if (ac.getAccountId() != null) {
builder.clause("accountId >= " + ac.getAccountId().getMin() + " AND accountId <= " + ac.getAccountId().getMax());
}
adapter.clause("username = \"%s\"", ac.getUserName());
adapter.clause("password = \"%s\"", ac.getPassword));
adapter.clause("email = \"%s\"", ac.getEmail());
PreparedStatement ps = connection.prepareStatement(builder.build().getQuery());
ResultSet rs = ps.executeQuery();
while (rs.next()) {
beans.add(new AccountBean(rs));
}
}
You can expand by adding further clause-methods to the adapter to handle specific objects like ranges in order to convert things like the accountId as well, e.g.
public void clauseMinMax(String format, Range r) {
if (r != null) {
builder.clause(String.format(format, r.getMin(), r.getMax()));
}
}
The accountId row then becomes (if getAccountId() returns a Range object):
adapter.clauseMinMax("accountId >= %d AND accountId <= %d", ac.getAccountId());
Use JSR305 and use the appropriate #Nonnull annotations and you don't have to do null checks, the annotations do them for you.
The use of #Nonnull and #CheckReturnValue annotations from JSR305 help to express the needs for null and return value checks. It is a good practice that the developer describes the expected behavior of the implementation for the later use and the static code analysis.
I have two lists of type object with data , the first one is principal entity and the second is dependent entity.
In addition I have key table that relate between the principal and depended entity objects.
In the first for statement I get one instance of type object and then I go and loop on every instance of the second entity and trying to find
Match between them (i think exponential problem…) ,if match is find update the principal entity with the reference object .
The following code is working but I check it from performance perspective and it's not working in efficient way.
Do you have an idea/tips how to improve this code from perforce aspect.
In the JVM monitor I found that EntityDataCreator.getInstanceValue have a problem.
This is the method start
// start with the principal entity
for (Object principalEntityInstance : principalEntityInstances) {
List<Object> genObject = null;
Object refObject = createRefObj(dependentMultiplicity);
// check entries in dependent entity
for (Object dependentEntityInstance : toEntityInstances) {
boolean matches = true;
for (String[] prop : propertiesMappings) {
// Get properties related keys
String fromProp = prop[0];
String toProp = prop[1];
Object fromValue = EntityDataCreator.getInstanceValue(fromProp, principalEntityInstance);
Object toValue = EntityDataCreator.getInstanceValue(toProp, dependentEntityInstance);
if (fromValue != null && toValue != null) {
if (!fromValue.equals(toValue)) {
matches = false;
break;
}
}
}
if (matches) {
// all properties match
if (refObject instanceof List) {
genObject = (List<Object>) refObject;
genObject.add(dependentEntityInstance);
refObject = genObject;
} else {
refObject = dependentEntityInstance;
break;
}
}
}
if (refObject != null) {
EntityDataCreator.createMemberValue(principalEntityInstance, navigationPropName, refObject);
}
}
public static Object getInstanceValue(String Property, Object EntityInstance) throws NoSuchFieldException,
IllegalAccessException {
Class<? extends Object> EntityObj = EntityInstance.getClass();
Field Field = EntityObj.getDeclaredField(Property);
Field.setAccessible(true);
Object Value = Field.get(EntityInstance);
Field.setAccessible(false);
return Value;
}
my guess would be your best bet is to go through both lists once, prepare all data that you need in hashtables, then do one iteration. this way, your problem becomes N+M instead of N*M
edit
Map<String,List<Object>> principalMap = new HashMap<String,List<Object>>();
for (Object principalEntityInstance : principalEntityInstances) {
List<String> keys = getKeysFor(principalEntityInstance);
for(String key : keys) {
List<Object> l = principalMap.get(key);
if(l==null) {
l = new ArrayList<Object>();
principalMap.put(key,l);
}
l.add(principalEntityInstance);
}
}
the do the same for dependentEntityInstance - this way, your searches will be much faster.
I might be misunderstanding your question, but I would suggest defining an equals method for your entities and a hashing method for them, so that you can leverage all the goodness that java already has for searching and matching entities already.
When at all possible rely on Java's infrastructure I think, Sun/Oracle spent a long time making it really fast.
This question already has answers here:
Retrieving the inherited attribute names/values using Java Reflection
(15 answers)
Closed 3 years ago.
I've recently changed my schema a bit so my classes inherit from a super class, problem is my comparison method which generates an audit log, using Java reflect, is now only looping through the fields of the child class, not the superclass, is there a way to get all the FIELDS? or do I need to cast it into the super class.....?
Heres my method below:
public static <T> String GenerateChangeLogForEntity(T old, T updated) {
String text = "";
try {
Field[] fields = old.getClass().getDeclaredFields();
if(fields != null) {
BaseController.getLogger().info("Z1 num fields:"+fields.length);
for (Field field : fields) {
if(field.isAnnotationPresent(Column.class)) {
String fieldName = field.getName();
BaseController.getLogger().info(field.getName());
if(field.isAnnotationPresent(Variation.class)) {
Variation v = field.getAnnotation(Variation.class);
fieldName = v.friendlyName();
}
field.setAccessible(true);
if(field.get(old) != null && field.get(updated) != null) {
if(!(field.get(old)).equals(field.get(updated))) {
text += "<p><span class=\"field-name\">"+fieldName+"</span> changed from: <strong>"+GetFriendlyFieldValueForChangeLog(field.get(old))+"</strong> to: <strong>"+GetFriendlyFieldValueForChangeLog(field.get(updated)) + "</strong></p>";
}
}
if(field.get(old) == null && field.get(updated) != null) {
text += "<p><span class=\"field-name\">"+fieldName+"</span> changed from: <strong>empty</strong> to: <strong>"+GetFriendlyFieldValueForChangeLog(field.get(updated)) + "</strong></p>";
}
if(field.get(old) != null && field.get(updated) == null) {
text += "<p><span class=\"field-name\">"+fieldName+"</span> changed from: <strong>"+GetFriendlyFieldValueForChangeLog(field.get(updated))+"</strong> to <strong>empty</strong>" + "</p>";
}
field.setAccessible(false);
}
}
}
} catch(IllegalAccessException e) {}
return text;
}
You can use this.getClass().getSuperClass() until this getSuperClass() method returns null to get the parent fields.
So, the best would be that you factorize your code. Implement one method that takes a list of Field as parameter and do your logical part within it, and a main method that search for fields through a while(superClass != null) loop.
Though it's late, I'm adding my suggestion since it's a nice solution.
Spring framework provide a nice Util class
org.springframework.util.ReflectionUtils this class has several methods which we can use.
To get a Field instance of an attribute from objectClass and superClasses I used ReflectionUtils.findField(clazz, fieldName);
Good thing with util is it doesn't throw an exception. Instead it returns null for invalid ones, so you can handle it gracefully.
Apache Commons Lang provides a method FieldUtils.getAllFields() which is an implementation of #sp00m's algorithm.