Design pattern for long if null statements for POJO object - java

I'm looking for a design pattern or even advice on some code that I saw the other day. The general structure is this (pseudo code):
public String getUrl(){
Person person= new Person();
StringBuilder builder = new StringBuilder();
if(person.getName() != null){
builder.append(",_name=");
builder.append(person.getName());
}
if(person.getLastName() != null){
builder.append(",_lastName=");
builder.append(person.getName());
}
if(person.getPostCode() != null){
builder.append(",_postCode=");
builder.append(person.getPostCode());
}
// So on and so forth
return builder.toString();
}
Now the problem is that I don't have control over Person class (I'm just given it via an API call). I was thinking to use reflection and a map like so:
Map<String, String> methodNameToUrlParameter; //Pre Build this map with method name and the actual parameter key
Map<String, String> urlParameterToValue;
Method[] methods = person.getMethods();
for(Method method: methods ){
String result = (String) method.invoke(person, null);
if(result != null){
String urlParam = methodNameToUrlParameter.get(method.getName());
urlToValue.put(urlParam, result );
}
}
Then I can go on my merry way. But this doesn't seem too great to me and I don't really know all too much about reflection, any ideas? Remember, I have no control over the Person class and it just has getters since it's immutable.
Thanks.
Edit:
What I am asking is there a better way to represent the flow of logic here with out using a too many if statements that do null checks. Perhaps a design pattern that I do not know about.
2nd Edit:
There's maybe like 20 if-null checks, which made things ugly. Is there a way todo it without none?

Use either Apache Commons ToStringBuilder or Guava's MoreObjects.ToStringHelper. Or get inspired by them.

For a minor change with better readability, you could pull the redundant code into its own method:
void AddField(StringBuilder builder, String value, String fieldName) {
if (value != null) {
builder.append(",_");
builder.append(fieldName);
builder.append("=");
builder.append(value);
}
}
which would simplify your code sample to the following:
public String getUrl(){
Person person= new Person();
StringBuilder builder = new StringBuilder();
AddField(builder, person.getName(), "name");
AddField(builder, person.getLastName(), "lastName");
AddField(builder, person.getPostCode(), "postCode");
// So on and so forth
return builder.toString();
}

Related

What is the most elegant way of doing null checks in Java

Giving an example, lets say we have a code like the one below:
String phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
As we know there is no elvis operator in Java and catching NPE like this:
String phone = null;
try {
phone = currentCustomer.getMainAddress().getContactInformation().getLandline()
} catch (NullPointerException npe) {}
Is not something anyone would advise. Using Java 8 Optional is one solution but the code is far from clear to read -> something along these lines:
String phone = Optional.ofNullable(currentCustomer).flatMap(Customer::getMainAddress)
.flatMap(Address::getContactInformation)
.map(ContactInfo::getLandline)
.orElse(null);
So, is there any other robust solution that does not sacrifice readability?
Edit: There were some good ideas already below, but let's assume the model is either auto generated (not convenient to alter each time) or inside a third party jar that would need to be rebuild from source to be modified.
The "heart" of the problem
This pattern currentCustomer.getMainAddress().getContactInformation().getLandline() is called TrainWreck and should be avoided. Had you done that - not only you'd have better encapsulation and less coupled code, as a "side-effect" you wouldn't have to deal with this problem you're currently facing.
How to do it?
Simple, the class of currentCustomer should expose a new method: getPhoneNumber() this way the user can call: currentCustomer.getPhoneNumber() without worrying about the implementation details (which are exposed by the train-wreck).
Does it completely solve my problem?
No. But now you can use Java 8 optional to tweak the last step. Unlike the example in the question, Optionals are used to return from a method when the returned value might be null, lets see how it can be implemented (inside class Customer):
Optional<String> getPhoneNumber() {
Optional<String> phone = Optional.empty();
try {
phone = Optional.of(mainAddress.getContactInformation().getLandline());
} catch (NullPointerException npe) {
// you might want to do something here:
// print to log, report error metric etc
}
return phone;
}
Per Nick's comment below, ideally, the method getLandline() would return an Optional<String>, this way we can skip the bad practice of swallowing up exceptions (and also raising them when we can avoid it), this would also make our code cleaner as well as more concise:
Optional<String> getPhoneNumber() {
Optional<String> phone = mainAddress.getContactInformation().getLandline();
return phone;
}
String s = null;
System.out.println(s == null);
or
String s = null;
if(s == null)System.out.println("Bad Input, please try again");
If your question was with the object being null, you should have made that clear in your question...
PhoneObject po = null;
if(po==null) System.out.println("This object is null");
If your problem is with checking whether all the parts of the line are null, then you should have also made that clear...
if(phone == null) return -1;
Customer c = phone.currentCustomer();
if(c == null)return -1;
MainAddress ma = c.getMainAddress();
if(ma == null) return -1;
ContactInfo ci = ma.getContactInformation();
if(ci == null)return -1;
LandLine ll = ci.getLandline();
if(ll == null)return -1;
else return ll.toNumber()//or whatever method
Honestly, code that's well written shouldn't have this many opportunities to return null.

Read methods from a text file and execute them in the program

I have a text file and that file lists all the operations that can be performed on a Pump Class.
example of the content of text file
Start PayCredit Reject Start PayCredit Reject TurnOff
....
.... so on.
These are the methods of the Pump class(Start(), Reject() etc)
I need to write a code where I can Read these method from the file one by one and execute them.
public static void main(String[] args) throws IOException
{
Pump gp= new Pump();
File file=new File("C:\\Users\\Desktop\\checker\\check.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
String line=null;
while((line=br.readLine())!=null)
{
String words[]=line.split(" ");
for(int i=0;i<words.length;i++)
{
String temp=words[i]+"()";
gp.temp; //compilation error
}
}
}
Could you tell me how can I achieve this functionality.
If you're not so familiar with reflection, maybe try using org.springframework.util.ReflectionUtils from the Spring Framework project?
The code would go something like this:
Pump gp = new Pump();
....
String temp = // from text file
....
Method m = ReflectionUtils.findMethod(Pump.class, temp);
Object result = ReflectionUtils.invokeMethod(m, gp);
You would need to use reflection to invoke the methods at runtime. Here is a simple example that assumes that all methods do not take any parameters.
Class<? extends Pump> pumpClass = gp.getClass();
String methodName = words[i];
Method toInvoke = pumpClass.getMethod(methodName);
if (null != toInvoke) {
toInvoke.invoke(gp);
}
First of all be aware that Java is not interpreted at runtime. So you can't do it this way.
If you already have the methods such as Start PayCredit Reject TurnOff and so on you can do it in the following way:
for(int i=0;i<words.length;i++)
{
String temp=words[i];
if (temp.equals("Start") gp.Start();
else if (temp.equals("PayCredit") gp.PayCredit();
...
}
use a switch case
for(int i=0;i<words.length;i++) {
String temp=words[i];
switch(temp) {
case "Start":
gp.start();
break;
case "PayCredit":
gp.PayCredit();
break;
}
}
You can use reflection to do this, e.g.
String line=null;
Method method = null;
while((line=br.readLine())!=null)
{
String words[]=line.split(" ");
for(int i=0;i<words.length;i++)
{
String temp=words[i];
method = getClass().getMethod(temp);
method.invoke(this);
}
}
That's assuming you want to call the method on this, of course, and that it's an instance method. Look at Class.getMethod and related methods, along with Method itself, for more details. You may want getDeclaredMethod instead, and you may need to make it accessible.
I would see if you can think of a way of avoiding this if possible though - reflection tends to get messy quickly. It's worth taking a step back and considering if this is the best design. If you give us more details of the bigger picture, we may be able to suggest alternatives.

Generic "quasi toString()" using Java Class reflection

I have been trying to create a robust code that prints out any Java class for debugging. For that, I use reflections.
In order to protect against recursive definition such as "Boolean contains static final Boolean TRUE", I ignore fields equal to their parents.
I use String += just out of laziness. It doesn't have to be efficient.
Yet, is there a nicer way to do recursive description of objects with reflections?
public String reflectionShowFields(Object parentObject) {
String stringData = "";
for (Field field:parentObject.getClass().getFields()) {
try {
Class<?> type = field.getType();
String typeSimpleName = type.getSimpleName();
Object fieldValue = field.get(parentObject);
String fieldName = field.getName();
if (type.isPrimitive() || type.isEnum() || CharSequence.class.isAssignableFrom(type)) {
stringData += String.format("%s: %s\n", fieldName, fieldValue);
} else if (Iterable.class.isAssignableFrom(type)) {
stringData += String.format(">>> %s[%s]: \n", fieldName, typeSimpleName);
for (Object item:(Iterable)fieldValue) {
stringData += reflectionShowFields(item);
}
stringData += String.format("<<< %s[%s]: \n", fieldName, typeSimpleName);
} else if (!fieldValue.equals(parentObject)) {
stringData += String.format(">>> %s[%s]: %s \n--------\n", fieldName, typeSimpleName, fieldValue.toString());
stringData+= reflectionShowFields(fieldValue);
stringData += String.format("<<< %s[%s]: \n", fieldName, typeSimpleName);
}
} catch (IllegalAccessException ignored) {}
}
return stringData;
}
You could use Apache commons-lang ReflectionToStringBuilder https://commons.apache.org/proper/commons-lang/apidocs/org/apache/commons/lang3/builder/ReflectionToStringBuilder.html
I don't think this is going to work.
Ignoring fields "that are equal to their parents" won't work. What if you have an A that refers to a B that refers back to the A.
You want to know about the cycles, and also the shared nodes in a DAG.
Iterating an Iterable can have side-effects, or it might never terminate, or it might throw exceptions.
Producing a readable rendering of an arbitrary graph is likely to really hard.
This is going to be an order of magnitude slower than a hand-built toString() method.
But think about it this way. If this was a good idea, there would be high profile 3rd-party libraries that did this kind of thing. And we'd all be using them already. It turns out that there ARE 3rd-party libraries, but you'd hardly call them high profile.
Incidentally, you could use JAXB or a JSON binding to render your POJOs as text. That achieves the same ends ...
Finally, your example of Boolean with a static field of type Boolean is not apropos. You wouldn't want to render static fields when displaying an instance.

Chaining order in Guava

I'm a bit new to Guava and it's style. I'm definitely digging it, but one thing I keep tripping over is the order of chained methods. Where I seem to have this problem the most is when using compound Orderings. I have to keep asking myself questions like:
Where does the natural go?
Where does the nullFirst (or last) go?
Which nullsFirst does what? (In the example below, one for host, one for last name, one for first name?)
Here's an example of one that I was just working on. It looks cumbersome, and I'm just not sure if I put it all together right. I have some JUnits to test it, and it seems okay, but there are always those quirky boundary cases.
Ordering<Host> lastNameThenFirstNameOrdering = Ordering.natural().nullsFirst().onResultOf(new Function<Host, String>() {
public String apply(Host host) {
return host.getLastName();
}}).compound(Ordering.natural().nullsFirst().onResultOf(new Function<Host, String>() {
public String apply(Host host) {
return host.getFirstName();
}})).nullsFirst();
As for an actual question: Is there a well-defined rule for how these things get executed? It seems to be last-to-first, but I'm having trouble telling that.
edit: Just wanted to point out the large, ugly code I was trying to replace:
Ordering<Host> ordering2 = new Ordering<Host>() {
public int compare(Host host1, Host host2) {
if (host1 == null || host2 == null) {
return host1 == host2 ? 0 : ((host1 == null) ? -1 : 1);
}
if(host1.getLastName() != null || host2.getLastName() != null){
if (host1.getLastName() == null) {
return -1;
} else if (host2.getLastName() == null) {
return 1;
}
if (host1.getLastName().compareTo(host2.getLastName()) != 0) {
return host1.getLastName().compareTo(host2.getLastName());
}
}
if (host1.getFirstName() == null) {
return -1;
} else if (host2.getFirstName() == null) {
return 1;
}
return host1.getFirstName().compareTo(host2.getFirstName());
}};
I think what you do is correct, but awfully ugly. Try this for readability:
Use an Enum
Move the functions to an enum that implements Function<Host, String>. Each of the enum items can provide it's own implementation.
enum HostFunctions implements Function<Host, String>{
GETFIRSTNAME{
#Override
public String apply(final Host host){
return host.getFirstName();
}
},
GETLASTNAME{
#Override
public String apply(final Host host){
return host.getLastName();
}
}
}
Indent your Code
Now reference those enum functions and indent your code properly. This is what it will look like:
final Ordering<Host> orderingByLastAndFirstName =
Ordering
.natural()
.nullsFirst()
.onResultOf(HostFunctions.GETLASTNAME)
.compound(
Ordering
.natural()
.nullsFirst()
.onResultOf(HostFunctions.GETFIRSTNAME))
.nullsFirst();
I'd say that makes everything much more understandable.
IDE Configuration
Regarding proper indentation (at least if you use Eclipse), see this question:
How to indent the fluent interface
pattern “correctly” with eclipse?
Enums as Functions
Regarding the enum: this is called the enum singleton pattern. The Guava guys use it all over their code base. Read about it on wikipedia or in Effective Java, Item 3. Although those sources both talk about single-item enums, the approach is almost the same here.
Each chaining call is "wrapping" the previous ordering into a new one, so you're right, the execution order can be thought of as "backwards".
I wrote and reviewed the Ordering class and I still regularly have to stop and scratch my head over the correct interleaving of nullsFirst(), and onResultOf() and reverse()!
The following would be my preference for doing this, assuming you must be able to handle null hosts, first names and last names. To me, it seems like a non-null first name and last name ought to be a requirement of the Host class. And you should generally try to avoid allowing collections to contain null objects.
Ordering<Host> lastNameFirstNameOrdering = new Ordering<Host>() {
#Override public int compare(Host left, Host right) {
return ComparisonChain.start()
.compare(left.getLastName(), right.getLastName(), Ordering.natural().nullsFirst())
.compare(left.getFirstName(), right.getFirstName(), Ordering.natural().nullsFirst())
.result();
}
}.nullsFirst();
Alternatively, I'd take an approach similar to Sean's but break things down for readability.
Ordering<Host> lastNameOrder = Ordering.natural().nullsFirst()
.onResultOf(Host.LAST_NAME);
Ordering<Host> firstNameOrder = Ordering.natural().nullsFirst()
.onResultOf(Host.FIRST_NAME);
Ordering<Host> orderingByLastAndFirstName =
lastNameOrder.compound(firstNameOrder).nullsFirst();
Keep in mind that you could also make these individual orderings static final fields of the class, allowing you to easily use them anywhere when sorting like Host.LAST_NAME_ORDER.

How to replace tokens in a string without StringTokenizer

Given a string like so:
Hello {FIRST_NAME}, this is a personalized message for you.
Where FIRST_NAME is an arbitrary token (a key in a map passed to the method), to write a routine which would turn that string into:
Hello Jim, this is a personalized message for you.
given a map with an entry FIRST_NAME -> Jim.
It would seem that StringTokenizer is the most straight forward approach, but the Javadocs really say you should prefer to use the regex aproach. How would you do that in a regex based solution?
Thanks everyone for the answers!
Gizmo's answer was definitely out of the box, and a great solution, but unfortunately not appropriate as the format can't be limited to what the Formatter class does in this case.
Adam Paynter really got to the heart of the matter, with the right pattern.
Peter Nix and Sean Bright had a great workaround to avoid all of the complexities of the regex, but I needed to raise some errors if there were bad tokens, which that didn't do.
But in terms of both doing a regex and a reasonable replace loop, this is the answer I came up with (with a little help from Google and the existing answer, including Sean Bright's comment about how to use group(1) vs group()):
private static Pattern tokenPattern = Pattern.compile("\\{([^}]*)\\}");
public static String process(String template, Map<String, Object> params) {
StringBuffer sb = new StringBuffer();
Matcher myMatcher = tokenPattern.matcher(template);
while (myMatcher.find()) {
String field = myMatcher.group(1);
myMatcher.appendReplacement(sb, "");
sb.append(doParameter(field, params));
}
myMatcher.appendTail(sb);
return sb.toString();
}
Where doParameter gets the value out of the map and converts it to a string and throws an exception if it isn't there.
Note also I changed the pattern to find empty braces (i.e. {}), as that is an error condition explicitly checked for.
EDIT: Note that appendReplacement is not agnostic about the content of the string. Per the javadocs, it recognizes $ and backslash as a special character, so I added some escaping to handle that to the sample above. Not done in the most performance conscious way, but in my case it isn't a big enough deal to be worth attempting to micro-optimize the string creations.
Thanks to the comment from Alan M, this can be made even simpler to avoid the special character issues of appendReplacement.
Well, I would rather use String.format(), or better MessageFormat.
String.replaceAll("{FIRST_NAME}", actualName);
Check out the javadocs for it here.
Try this:
Note: The author's final solution builds upon this sample and is much more concise.
public class TokenReplacer {
private Pattern tokenPattern;
public TokenReplacer() {
tokenPattern = Pattern.compile("\\{([^}]+)\\}");
}
public String replaceTokens(String text, Map<String, String> valuesByKey) {
StringBuilder output = new StringBuilder();
Matcher tokenMatcher = tokenPattern.matcher(text);
int cursor = 0;
while (tokenMatcher.find()) {
// A token is defined as a sequence of the format "{...}".
// A key is defined as the content between the brackets.
int tokenStart = tokenMatcher.start();
int tokenEnd = tokenMatcher.end();
int keyStart = tokenMatcher.start(1);
int keyEnd = tokenMatcher.end(1);
output.append(text.substring(cursor, tokenStart));
String token = text.substring(tokenStart, tokenEnd);
String key = text.substring(keyStart, keyEnd);
if (valuesByKey.containsKey(key)) {
String value = valuesByKey.get(key);
output.append(value);
} else {
output.append(token);
}
cursor = tokenEnd;
}
output.append(text.substring(cursor));
return output.toString();
}
}
With import java.util.regex.*:
Pattern p = Pattern.compile("{([^{}]*)}");
Matcher m = p.matcher(line); // line being "Hello, {FIRST_NAME}..."
while (m.find) {
String key = m.group(1);
if (map.containsKey(key)) {
String value= map.get(key);
m.replaceFirst(value);
}
}
So, the regex is recommended because it can easily identify the places that require substitution in the string, as well as extracting the name of the key for substitution. It's much more efficient than breaking the whole string.
You'll probably want to loop with the Matcher line inside and the Pattern line outside, so you can replace all lines. The pattern never needs to be recompiled, and it's more efficient to avoid doing so unnecessarily.
The most straight forward would seem to be something along the lines of this:
public static void main(String[] args) {
String tokenString = "Hello {FIRST_NAME}, this is a personalized message for you.";
Map<String, String> tokenMap = new HashMap<String, String>();
tokenMap.put("{FIRST_NAME}", "Jim");
String transformedString = tokenString;
for (String token : tokenMap.keySet()) {
transformedString = transformedString.replace(token, tokenMap.get(token));
}
System.out.println("New String: " + transformedString);
}
It loops through all your tokens and replaces every token with what you need, and uses the standard String method for replacement, thus skipping the whole RegEx frustrations.
Depending on how ridiculously complex your string is, you could try using a more serious string templating language, like Velocity. In Velocity's case, you'd do something like this:
Velocity.init();
VelocityContext context = new VelocityContext();
context.put( "name", "Bob" );
StringWriter output = new StringWriter();
Velocity.evaluate( context, output, "",
"Hello, #name, this is a personalized message for you.");
System.out.println(output.toString());
But that is likely overkill if you only want to replace one or two values.
import java.util.HashMap;
public class ReplaceTest {
public static void main(String[] args) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("FIRST_NAME", "Jim");
map.put("LAST_NAME", "Johnson");
map.put("PHONE", "410-555-1212");
String s = "Hello {FIRST_NAME} {LAST_NAME}, this is a personalized message for you.";
for (String key : map.keySet()) {
s = s.replaceAll("\\{" + key + "\\}", map.get(key));
}
System.out.println(s);
}
}
The docs mean that you should prefer writing a regex-based tokenizer, IIRC. What might work better for you is a standard regex search-replace.
Generally we'd use MessageFormat in a case like this, coupled with loading the actual message text from a ResourceBundle. This gives you the added benefit of being G10N friendly.

Categories

Resources