get object property by finding its class - java

I have game objects in an array collection, but they can be different classes. I can find the object by its coordinates:
Object obb = grid.getCellContent(insertObjectX, insertObjectY);
What I need to do is to find if obb.canBeSubmerged == true and then simply move it to another array.
The problem is that I canot get a property of that object "canBeSubmerged" because compilier does not know which class I used.
I wonder if there is a quicker way to do it then to go through "obb.getClass() == myClass.class" statements for each of the possible object classes.
.
.
EDIT: based on stuckless suggestion here is a working solution:
try {
java.lang.reflect.Field f1 = obb.getClass().getField("canBeSubmerged");
java.lang.reflect.Field f2 = obb.getClass().getField("subObject");
if (f1 != null) {
canBeSubmerged = f1.getBoolean(obb);
f2.setBoolean(obb, canBeSubmerged);
}
}catch (Exception e) { }
//enter it into the submerged grid level and remove from the top grid level
if (canBeSubmerged){
grid.removeObject(insertObjectX, insertObjectY);
grid.putSubObjectInCell(insertObjectX, insertObjectY, obb);
}

If your obb object that contains the canBeSubmerged property is always of a particular class type, such as MyOBB.class, then you can do this...
if (obb instanceof MyOBB.class) {
if (((MyOBB)obb).canBeSubmerged) {
// do your work
}
}
========= OR ============
Using Reflection (which will be slower)
try {
Field f = obb.getClass().getField("canBeSubmerged");
if (f!=null && f.getBoolean(obb)) {
// do your work
}
} catch (Exception e) {
}

Your objects should probably all extend a common superclass or implement a common interface which defines a method
public boolean canBeSubmerged();
You should not use public fields. And also note that
if (obb.canBeSubmerged() == true)
can be written as
if (obb.canBeSubmerged())
which is more logical and readable.

If you are only interested in one attribute of the object your could extract that to an interface
public interface Submergable {
boolean isSubmerged();
}
And let all objects that may submerge implement it.
Then you can do Object instanceof Submergable

Related

a method validating objects from different roots repeats most of checks

please is there a way how to make the code more concise -
to avoid repeating similar/same actions -
I have a method doing object validations, but most parameters
are similar/same, like using some sort of lambda expression for that,
but objects are not from the same tree.
My use-case is like this:
validate.( car );
and somewhere else I do:
validate.( person );
Right now I am doing the validation like this:
public boolean validate( Object obj ) {
if ( obj instanceof Car ) {
Car car = (Car) obj;
if ( car.getAge() <= 0 ) return false;
// many other checks which are repeated below
} else if ( obj instanceof Person ) {
Person person = (Person) obj;
if ( person.getAge() <= 0 ) return false;
// many other check which are repeating those above
}
// here I would like to do checks for both objects, but objects are from different roots
return true;
}
You can use method overloading :
public boolean validate(Car car) {
if ( car.getAge() <= 0 ) return false;
return validate((Master)car);
}
public boolean validate(Person p) {
if ( p.getAge() <= 0 ) return false;
return validate((Master)p);
}
public boolean validate(Master m) {
// common validations
return true;
}
Master is the common parent of Person and Car (I assume there is a common parent interface/class).
"Do not"s:
First of all, I would strictly suggest you to try your best to avoid designing your method as you are doing it now;
Person and Car have nothing in common from the logical, modelling, or conceptual perspective. Nor they do share any similar characteristics in the real life;
Do not accept Object as an argument in your method. You will have hard times of managing your bugs and/or maintaining unpredictable behaviour.
"Do"s:
Define your method by following Single Responsibility Principle;
Consider from your model object perspective - what your method should be as a behaviour? what ONE problem it should solve?
Try to separate concerns in their respective classes/files/block-units and try not to overlap them.
If you want to your method to behave based on what is the actual instance of the argument, best way is to use instanceof checks.
What you can do instead, however, is to design some proper inheritance and accept a supertype, as a method argument. Then polymorphism would kick in and you will only have one logic in your method.

How to optimize code below by getting rid of redundant?

My code below is to calculate ProductFunction based on some values of Object Product. Method getProductFunctions in InternalProductMapper and ExternalProductMapper call functions in ProductFunctionCalculator to calcuate the value of ProductFunction. According to me its not possible to have a single function in ProductFunctionCalculator, because two different mappers call it. How can I optimize the code below? Also, If I have two functions, i am not sure what to name the other as both calculate function for two different mappers.
public class InternalProductMapper{
public EnumSet<ProductFunction> getProductFunctions(Product p){
return productFunctionCalculator.get(p);
}
}
public class ExternalProductMapper{
public EnumSet<ProductFunction> getProductFunctions(Product p){
return p!=null ? productFunctionCalculator.calculate(p):
return EnumSet.of(Function.BUSINESS,Function.MARKET);
}
}
public class ProductFunctionCalculator{
public EnumSet<ProductFunction> calculate(Product p){
if(p.brand() == "ABC" && p.id.equals("1") && p.value > 100){
return EnumSet.of(Function.BUSINESS, Function.LOCAL);
}
}
public EnumSet<ProductFunction> get(Product p){
if(p != null && p.location.equals("NY")){
return EnumSet.of(Function.BUSINESS);
}
return EnumSet.of(Function.BUSINESS, Function.MARKET);
}
}
"Also, If I have two functions, i am not sure what to name the other as both calculate function for two different mappers."
You can name one calculateInternal and the other calculateExternal or similar, unless I misunderstand what you mean to say.
You can also add an Identifier on your Product object, to ascertain if it is internal or external(Could be a new field, boolean/enum or otherwise). You would need to set the value of this field on initialization of the Product object, when you most probably know what kind of Product it is. This could allow for a new single method of calculating, because now your method would know how to handle the different scenarios(As you have this new 'type' field), possibly via an if-else statement such as:
//This should not be allowed if you can help it and you should try and get
//rid of the scenario this comes in as null - just check it before calling this method
if(product != null) {
if(product.isInternal()) {
//Internal product logic
} else {
//External product logic
}
}

Create Java Object On-Demand

I have a java private method and I am trying to find the best way to create an object inside the method. Following are two different approaches that I am trying:
Approach A:
private void createObject() {
Object A;
if (conditionA) {
A = new Object();
//do some Action X with object A
} else {
//Do something without object A
if (conditionB) {
return;
}
A = new Object();
//do some Action Y with object A
}
return;
}
Approach B:
private void createObject() {
Object A = new Object()
if (conditionA) {
//do some action X with Object A
} else {
//Do something without Object A
if (conditionB) {
return;
}
//do some action Y with Object A
}
return;
}
Obviously both the code snippets are working and without any issues. I am just trying to find out the better coding style and standard.
Let's write the truth table
A | B | Expected Outcome
-----+-------+-------------------------------
True | True | do X with object A
True | False | do X with object A
False| False | do Y with object A
False| True | do something without object A
-----+-------+-------------------------------
I think this translates to:
boolean doXWithA = conditionA;
boolean doYWithA = !conditionA && !conditionB;
boolean doSomethingWithA = doXWithA || doYWithA;
if(doSomethingWithA)
Object a = new Object();
if (doXWithA) {
// do X with object A
} else if (doXWithB) {
// do X with object B
}
} else {
// do something without object A
}
Good practice is to reduce the scope of variables as much as possible. And if the instantiation is expensive, you also want to reduce the number of time you instantiate it.
Here Object a is only initialised when necessary and its scope is as small as possible (only one if block)
I believe that if you want to initialize object with default value you should do this in the place of declaration
Object A = new Object();
if (conditionA) {
...
}
Approach A is better.
In that, Consider "if" condition is not satisfied and it goes in "else".
There if conditionB is satisfied, then it will return.So memory is not allocated to A.
In Approach B, unnecessarily memory allocation is done which is of no use in above scenario.
I would go with approach A, as it is only necessary to initialize the object when needed.
If the initialization of that object is rather complicated, in order to avoid repeating yourself, you either define a static helper method in order to initialize the object or you go via a Supplier<>:
Supplier<Type> objSupplier = () -> new Type(a, b, c, d, whatever)
and then, at the two places where the object is supposed to be created, you do
A = objSupplier.get();
(note that variables are usually written in lowercase/camelCase).

Check an replace null values in multiple variables java

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).

How to get the fields in an Object via reflection?

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.

Categories