Try this. The initial reflection is certainly expensive, but if you're going to use it many many times, which I think you will, this is most certainly a better solution what what you're proposing. I don't like using reflection, but I find myself using it when I don't like the alternative to reflection. I do think that this will save your team a lot of headache, but you must pass the name of the method (in lowercase).
In other words, rather than pass "name", you would pass "fullname" because the name of the get method is "getFullName()".
Map<String, Method> methodMapping = null;
public Object getNode(String name) {
Map<String, Method> methods = getMethodMapping(contact.getClass());
return methods.get(name).invoke(contact);
}
public Map<String, Method> getMethodMapping(Class<?> contact) {
if(methodMapping == null) {
Map<String, Method> mapping = new HashMap<String, Method>();
Method[] methods = contact.getDeclaredMethods();
for(Method method : methods) {
if(method.getParameterTypes().length() == 0) {
if(method.getName().startsWith("get")) {
mapping.put(method.getName().substring(3).toLower(), method);
} else if (method.getName().startsWith("is"))) {
mapping.put(method.getName().substring(2).toLower(), method);
}
}
}
methodMapping = mapping;
}
return methodMapping;
}
If you need to access data contained within members of contact, you might consider building a wrapper class for contact which has all methods to access any information required. This would also be useful for guaranteeing that the names of the access fields will always remain the same (I.e. if wrapper class has getFullName() and you call with fullname, it will always work even if contact's getFullName() has been renamed -- it would cause compilation error before it would let you do that).
public class ContactWrapper {
private Contact contact;
public ContactWrapper(Contact contact) {
this.contact = contact;
}
public String getFullName() {
return contact.getFullName();
}
...
}
This solution has saved me several times, namely when I wanted to have a single data representation to use in jsf datatables and when that data needed to be exported into a report using jasper (which doesn't handle complicated object accessors well in my experience).
I was wondering the if if-else statements, is like a switch statement that does not have a break statement.
That's backwards. Kind of.
An if, else if, ... else sequence in which all of the tests are all simple equality tests on the same variable of the form (variable == value)
or ((variable == value1) || (variable == value2) ...)
can be converted to a switch statement on that variable. The (variable == value)
tests become case value:
, and the body of the if
(or else if
) becomes the body of the case, but you need to add a break
statement at the end of the case body. The ((variable == value1) || (variable == value2) ...)
tests become a sequence of cases of the form case value1: case value2: ... case valuen:
An if sequence with more complex tests is in general distinct from a switch statement.
If every case in a switch statement ends with break
, that switch statement can always be rewritten as an if, else if, ... sequence. This conversion from a switch to an if sequence is also possible when fall through is limited to things such as case A: case B: ... case N: do_something(); break;
Fall through in which a non-empty body falls through to another non-empty body is not directly convertible to an if sequence.
Best Answer
Hash codes are not unique. There are numerous strings which hash to, say,
1234546
. If you want to check for the string"foo"
and the unrelated, meaningless string"bar"
has the same hash, your code will falsely treat"bar"
the same as"foo"
rather than rejecting it/going todefault
.Fixing this is generally possible (check whether the value really
equals
the intended string in each case), but it's quite a bit of extra code, especially if there is adefault
case (since you have to transfer control out of the "wrong" case and to the default case). This is how the switch-over-string feature proposal desugars it. It's not pretty.Hash codes are not meaningful. Someone has to find out the hash code and hard-code them, and the code has more meaningless magic numbers. You can and should of course write the string in a comment next to the integer literal, but it's still a maintenance burden.
Technically, the hash algorithm might also change when the JVM is updated or when the deployment environment is changed, etc. — depending on the JVM, maybe even when the JVM is restarted! And then the code would be silently wrong. This probably won't actually happen (I think the implementation of Java 7 switch-over-string depends on the compiler being able to predict the
hashCode
value of string literals).