A better way of code generator in Java?
Another solution would be to stick to the current technology but provide a small layer with the builder pattern. To implement the builder you need a small one time effort, but get much better readable code.
I implemented the first part of your code. With the proper builder you could write:
graph = new GraphBuilder()
.createNode(3).setLabel("3").setDescription("null").add()
.createNode(2).setLabel("2").setDescription("null").add()
.createNode(1).setLabel("1").setDescription("Accepted").add()
.createNode(0).setLabel("0").setDescription("Initial").add()
// unimplemented start
.createEdge(2, 1).setLabel("0").add()
.createEdge(2, 2).setLabel("1").add()
.createEdge(1, 1).setLabel("0").add()
.createEdge(1, 3).setLabel("1").add()
.createEdge(0, 1).setLabel("0").add()
.createEdge(0, 2).setLabel("1").add()
// unimplemented end
.build();
Much more readable, isn't it? To get this you need two builders. First comes the GraphBuilder:
package at.corba.test.builder;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Builder for generating graphs.
* @author ChrLipp
*/
public class GraphBuilder {
/** List of StateBuilder, accesable via nodeNumber. */
Map<Integer, StateBuilder> stateBuilderMap = new LinkedHashMap<Integer, StateBuilder>();
/**
* Delegates node-specific building to NodeBuilder.
* @param nodeNumber Number of node to create
* @return NodeBuilder for the node instance to create.
*/
public StateBuilder createNode(final int nodeNumber) {
StateBuilder builder = new StateBuilder(this);
stateBuilderMap.put(nodeNumber, builder);
return builder;
}
/**
* Builder function to initialise the graph.
*/
public SetBasedDirectedGraph build() {
SetBasedDirectedGraph graph = new SetBasedDirectedGraph();
for (int key : stateBuilderMap.keySet()) {
StateBuilder builder = stateBuilderMap.get(key);
State state = graph.createNode(key);
state = builder.build(state);
graph.addNode(state);
}
return graph;
}
}
and than the StateBuilder:
package at.corba.test.builder;
import java.util.HashMap;
import java.util.Map;
/**
* Builder for generating states.
* @author ChrLipp
*/
public class StateBuilder {
/** Parent builder */
private final GraphBuilder graphBuilder;
/** Properties for this node */
Map<GraphProperties, String> propertyMap = new HashMap<GraphProperties, String>();
/**
* ctor.
* @param graphBuilder Link to parent builder
* @param nodeNumber Node to create
*/
public StateBuilder(final GraphBuilder graphBuilder) {
this.graphBuilder = graphBuilder;
}
/**
* Property setter for property Label.
* @param label value for property label
* @return current NodeBuilder instance for method chaining
*/
public StateBuilder setLabel(final String label) {
propertyMap.put(GraphProperties.LABEL, label);
return this;
}
/**
* Property setter for description Label.
* @param description value for description label
* @return current NodeBuilder instance for method chaining
*/
public StateBuilder setDescription(final String description) {
propertyMap.put(GraphProperties.DESCRIPTION, description);
return this;
}
/**
* DSL function to close the node section and to return control to the parent builder.
* @return
*/
public GraphBuilder add() {
return graphBuilder;
}
/**
* Builder function to initialise the node.
* @return newly generated node
*/
public State build(final State state) {
for (GraphProperties key : propertyMap.keySet()) {
String value = propertyMap.get(key);
state.setProperty(key, value);
}
return state;
}
}
You would do the same for edges, but I did not implement this :-) . In Groovy it is even more easier to create builders (my implementation is a builder written in Java), see for example Make a builder.
A better way of code generator in Java... How about tools like ANTLR, which is a modern tool created specifically for implementing lexers/parsers with code generation support. It has great documentation, including two books:
- The Definitive ANTLR Reference
- Language Implementation Patterns
The last one is useful even when not using ANTLR.
A very simple example is given on the following blog :
http://namanmehta.blogspot.in/2010/01/use-codemodel-to-generate-java-source.html
You might want to have a look at it.
The problem with jcodemodel is that it is internally used by popular code generators like JAX-B and is not well documented. It also don't have any tutorials. But if you want to use this library, you can have a look at different blogs where the users have documented their experience / problem description and resolution .
Best of luck