Robert has several years of professional experience and a PhD in the field of automated software migrations. He is the co-founder and CEO of Numition Ltd., a start-up company specialized in developing software migrators. Robert is a DZone MVB and is not an employee of DZone and has posted 10 posts at DZone. You can read more from them at their website. View Full User Profile

Language Construct vs. Design Pattern - PHP Arrays In Java

10.24.2008
| 9319 views |
  • submit to reddit

Automated migration is a difficult task because of many reasons. One of them is the need to ensure a good code quality for the generated code. Migrating from PHP to Java in particular is even more difficult, since the languages are so different in terms of execution models (interpreted vs. dynamic), type systems (loose-dynamic vs. strict-static) and so on.

The PHP Arrays Problem

A particular problem is the use of PHP associative arrays to build data structures, even if classes would have been a better choice. For constructing arrays, PHP provides a dedicated language construction, allowing the following:

$a = array("entry1",
"key2" => "entry2",
array("key31", "nested entry"));

The nTile PHP runtime library provides the Array and ArrayEntry classes to emulate this concept. However, by going the traditional way, the generated code can look overly complex in comparison:

a = new Array(new ArrayEntry("entry1"),
new ArrayEntry("key2", "entry2"),
new ArrayEntry(
new Array(
new ArrayEntry("key31",
"nested entry" ));

There are lots of things to deal with in building a software migrator from PHP to Java, so improving this wasn’t that high on our list of priorities. But then we remembered the fluid interfaces pattern, which we were already using with the Apache Commons Lang library.

Design pattern to the resque

In Java, one overrides the Object.equals(Object) to properly check object equality and the Object.hashCode() method when placing objects in hashtables. Coding them by hand is tedious and the EqualsBuilder and HashCodeBuilder classes of Commons Lang simplify the process, like in this case:

new EqualsBuilder()
.appendSuper(super.equals(obj))
.append(field1, rhs.field1)
.append(field2, rhs.field2)
.isEquals()

As a consequence, we defined the ArrayBuilder class with the following signature:

public class ArrayBuilder<V> {
public ArrayBuilder() { }
public ArrayBuilder<V> put(Object key, V value) { }
public ArrayBuilder<V> put(V value) { }
public Array<V> getArray() { }
}

Using ArrayBuilder for the migration of the PHP code presented above is straightforward:

a = new ArrayBuilder<Object>()
.put("entry1")
.put("key2", "entry2")
.put(new ArrayBuilder<String>()
.put("key31", "entry3")
)
.getArray();

While the above code is still a bit more complex than the one in PHP, it provides the benefit of generics. This way it is easy to see that the array is supposed to hold all kinds of data, hence the Object generic parameter. And also that the array from the third entry will always contain strings. This information will also ease the transition to object-oriented data structures as the application evolves.

Conclusions

It is difficult to maintain the simplicity of a programming language, because one is tempted to add new constructs that ease certain tasks. We can see this happening with all the talk around the JSRs that should be made part of the Java 7 language specification. This is especially true for the language level XML support feature.

In this post I wanted to point out that this is not always the best approach. Sometimes changing the coding pattern is sufficient to solve your problems.

References
Published at DZone with permission of Robert Enyedi, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

mark taylor replied on Fri, 2008/10/24 - 1:48pm

Nice solution to a tough problem! Thanks for sharing.

Aljoscha Rittner replied on Sat, 2008/10/25 - 1:11pm

Hi!

With static imports and varargs it could be easier.

Implement your put methods as static factory methods of ArrayEntry objects and use a static import.

import static com.example.ArrayBuilder.*

ArraySet a = entries (
entry ("Simple String"),
entry ("Key", "Value"),
entries (
entry ("Key2", "Value")
)
);

// Non-Generic sample...
public class ArrayBuilder {
public static ArraySet entries (ArrayEntry... someEntries) {...}
public static ArrayEntry entry (String key, String value) {...}
public static ArrayEntry entry (String keyOnly) {...}

}

public interface ArraySet extends ArrayEntry {...}

public interface ArrayEntry {...}

best regards,
josh.

Robert Enyedi replied on Sun, 2008/10/26 - 9:11am in response to: Aljoscha Rittner

@Josh: Interesting solution. My only concern is about potential signature overlappings caused by the group static import. But maybe that isn't such a big problem after all.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.