... is a small Java framework that helps you make immutable, thread-safe, versionable objects. Spend less time on boring boilerplate code and more time solving problems.
-
Create an interface with getters:
@GrainSchema public interface Order { String getProduct(); int getQuantity(); }
-
Run the Grains Maven plugin.
-
Use the generated Factory, Builder, and Grain classes:
OrderBuilder builder = OrderFactory.newBuilder(); builder.setProduct("apples"); builder.setQuantity(13); OrderGrain order = builder.build(); System.out.println(order instanceof Order); // prints: true System.out.println(order.getProduct()); // prints: apples System.out.println(order instanceof Map); // prints: true System.out.println(order.get("quantity")); // prints: 13 System.out.println(order.entrySet()); // prints: [product=apples, quantity=13] OrderGrain changed = order.withQuantity(9); // immutable :) System.out.println(changed); // prints: {product=apples, quantity=9} System.out.println(order); // prints: {product=apples, quantity=13} changed = changed.with("RMA", "9928"); // extensible and versionable :) System.out.println(changed); // prints: {product=apples, quantity=9, RMA=9928}
Jackson serialization to JSON, Smile, YAML, etc. (with the grains-jackson library):
ObjectMapper mapper = JacksonTools.newGrainsObjectMapper();
String json = mapper.writeValueAsString(order);
OrderGrain restored = mapper.readValue(json, OrderGrain.class);
System.out.println(json); // prints: {"product":"apples","quantity":13}
System.out.println(restored.equals(order)); // prints: true
Kryo serialization (with the grains-kryo library):
Kryo kryo = KryoTools.newGrainsKryo();
Output output = new Output(1024);
kryo.writeClassAndObject(output, order);
output.close();
Input input = new Input(output.getBuffer(), 0, output.total());
Object thawed = kryo.readClassAndObject(input);
System.out.println(thawed.equals(order)); // prints: true
MessagePack serialization (with the grains-msgpack library):
MessagePack msgpack = MessagePackTools.newGrainsMessagePack();
byte[] data = msgpack.write(order);
OrderGrain unpacked = msgpack.read(data, OrderGrain.class);
System.out.println(unpacked.equals(order)); // prints: true
Native support for Java serialization:
ByteArrayOutputStream out = new ByteArrayOutputStream();
new ObjectOutputStream(out).writeObject(order);
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
Object read = new ObjectInputStream(in).readObject();
System.out.println(read.equals(order)); // prints: true
The Grains framework (published on Maven Central) requires Java 7 or greater, and Maven 2.2.1 or greater.
-
Create a new package to contain your object model, for example: com.acme.model
-
Configure your POM to pre-compile this package during the generate-sources phase:
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> <executions> <execution> <phase>generate-sources</phase> <goals><goal>compile</goal></goals> <configuration> <includes> <include>com/acme/model/**</include> </includes> </configuration> </execution> </executions> </plugin>
-
Configure the grains-plugin to run during the generate-sources phase:
<plugin> <groupId>net.nullschool</groupId> <artifactId>grains-plugin</artifactId> <version>0.8.0</version> <executions> <execution> <phase>generate-sources</phase> <goals><goal>generate</goal></goals> </execution> </executions> </plugin>
-
Add a dependency on grains-core:
<dependency> <groupId>net.nullschool</groupId> <artifactId>grains-core</artifactId> <version>0.8.0</version> </dependency>
-
(optional) Add a dependency on the serialization library of your choice, such as:
<dependency> <groupId>net.nullschool</groupId> <artifactId>grains-jackson</artifactId> <version>0.8.0</version> </dependency>
Done! Any interface in com.acme.model annotated with @GrainSchema will have a grain implementation generated when mvn compile is invoked. By default, all generated sources appear in the target/generated-sources/grains/com/acme/model directory.
See the wiki for more details.
Clojure's defrecord macro provided the main inspiration for grains.
Grains uses Semantic Versioning