#What does it do?
beanprocessor creates boilerplate for JavaBeans by generating a superclass. It works with Eclipse's annotation support as a factory, and also works with maven 3's compiler plugin, which supports pluggable annotation processors. beanprocessor can create getters and setters. It can also create a "fluent" setting API, generate Guava-compatible predicates and extractor functions, and emit some JAXB XML annotations.
There's also a tuple generation facility, for both generic tuples and specialized tuple types including primitives. Generic tuples look like this:
publicclassTuple2<A, B> {
publicfinalA_1;
publicfinalB_2;
...
}Specialized tuples use primitives, so a tuple type that holds a double and a String can look like this:
publicclassDoubleString {
publicfinaldouble_1;
publicfinaljava.lang.String_2;
...
}beanprocessor does the things that I am interested in, right now. It's not a replacement for the javadude annotation processor yet, if you use a lot of the features of that.
#Usage
Your build section needs to set the compiler to use source and targe versions of at least 1.6, and add the bean processor as a dependency to the compiler plugin. It's also useful to insert build-helper-maven-plugin so Eclipse will add the generated annotation source to a source directory. Here's an example of the build section:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
<dependencies>
<dependency>
<groupId>com.soletta</groupId>
<artifactId>beanprocessor</artifactId>
<version>0.1.4-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>target/generated-sources/annotations</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I usually set up a separate project to contain the generated beans, then include that project in others that want to use the beans.
##Adding Annotations
Add annotations to your bean class to generate stuff:
@XmlRootElement@SBean(properties={
@SProperty(name="title"),
@SProperty(name="running", type=boolean.class, javadoc="Determines if the job is running."),
@SProperty(name="started", type=Date.class, jaxbType=JAXBMemberType.ELEMENT),
@SProperty(name="number", type=double.class, jaxbType=JAXBMemberType.TRANSIENT)
}, bound=true, predicates=true, extractors=true, fluent=true, jaxbType=JAXBMemberType.ATTRIBUTE)
publicclassTestJobextendsTestJobBase { }Each type of generator set at the bean level, has a corresponding setting at the property level, plus a no setting, to override.
bound at the bean level makes every property a bound property, by default. At the property level, you can turn it off with nobound. Even if bound isn't set on the SBean annotation, you can set it on the SProperty annotation.
Sample output is at the end of this document.
Create a package-info.java file, in the package you want tuple classes generated into. On the package declaration, add a Tuples annotation if you want generic tuples, and/or add a Specialized annotation to create particular optimized tuple types. Here's an example:
@Tuples(20)
@Specialize({
@Tuple(tupleTypeName="AllPrims", value={byte.class, short.class, int.class, long.class, char.class, float.class, double.class}),
@Tuple(value={byte.class, short.class, int.class, long.class, char.class, float.class}),
@Tuple(tupleTypeName="DoubleString", value={double.class, String.class})
})
packageptest;
importcom.soletta.beanprocessor.Specialize;
importcom.soletta.beanprocessor.Tuple;
importcom.soletta.beanprocessor.Tuples;Note again that you must annotate the package, in the package-info.java file.
The generated tuples support equals and hashCode. They also have a toArray() (and a toArray(Object[])) method.
To construct a generic tuple, call Tuples.of(field1, field2, ...).
To construct a specialized tuple, call SpecializeTuple.of(field1, field2, ...);
##Using the Guava predicates
A HAS_ predicate is constructed for each property that isn't a primitive. Boolean properties get an IS_ predicate. Use them like this:
TestJobjob = newTestJob();
job.setTitle("I have a title");
List<TestJob> jobs = asList(job, newTestJob());
assertEquals(1, filter(jobs, TestJob.HAS_TITLE).size());#Using the Guava extractors
A Guava function is created for each property:
Collection<Double> helloValues = Collections2.transform(jobs, TestJob.NUMBER);
for (Doublev: helloValues)
System.out.println(v);##Output
TestJob's annotations will generate the following:
packageptest;
@javax.annotation.Generated(value = "com.soletta.processor.BeanProcessor")
abstractpublicclassTestJobBase {
protectedTestJobBase() {
}
privatejava.lang.Stringtitle;
@javax.xml.bind.annotation.XmlAttributepublicjava.lang.StringgetTitle() {
returntitle;
}
publicvoidsetTitle(java.lang.Stringtitle) {
java.lang.StringoldValue = this.title;
this.title = title;
propertyChangeSupport.firePropertyChange("title", oldValue, title);
}
publicTestJobtitle(java.lang.StringfluentValue) {
setTitle(fluentValue);
return (TestJob) this;
}
publicfinalstaticcom.google.common.base.Predicate<TestJobBase> HAS_TITLE = newcom.google.common.base.Predicate<TestJobBase>() {
publicbooleanapply(TestJobBasevalue) {
returnvalue.getTitle() != null;
}
};
publicfinalstaticcom.google.common.base.Function<TestJobBase, java.lang.String> TITLE = newcom.google.common.base.Function<TestJobBase, java.lang.String>() {
publicjava.lang.Stringapply(TestJobBasevalue) {
returnvalue.getTitle();
}
};
privatebooleanrunning;
/** Determines if the job is running. */@javax.xml.bind.annotation.XmlAttributepublicbooleanisRunning() {
returnrunning;
}
publicvoidsetRunning(booleanrunning) {
booleanoldValue = this.running;
this.running = running;
propertyChangeSupport.firePropertyChange("running", oldValue, running);
}
publicTestJobrunning(booleanfluentValue) {
setRunning(fluentValue);
return (TestJob) this;
}
publicfinalstaticcom.google.common.base.Predicate<TestJobBase> IS_RUNNING = newcom.google.common.base.Predicate<TestJobBase>() {
publicbooleanapply(TestJobBasevalue) {
returnvalue.isRunning();
}
};
publicfinalstaticcom.google.common.base.Function<TestJobBase, java.lang.Boolean> RUNNING = newcom.google.common.base.Function<TestJobBase, java.lang.Boolean>() {
publicjava.lang.Booleanapply(TestJobBasevalue) {
returnvalue.isRunning();
}
};
privatejava.util.Datestarted;
publicjava.util.DategetStarted() {
returnstarted;
}
publicvoidsetStarted(java.util.Datestarted) {
java.util.DateoldValue = this.started;
this.started = started;
propertyChangeSupport.firePropertyChange("started", oldValue, started);
}
publicTestJobstarted(java.util.DatefluentValue) {
setStarted(fluentValue);
return (TestJob) this;
}
publicfinalstaticcom.google.common.base.Predicate<TestJobBase> HAS_STARTED = newcom.google.common.base.Predicate<TestJobBase>() {
publicbooleanapply(TestJobBasevalue) {
returnvalue.getStarted() != null;
}
};
publicfinalstaticcom.google.common.base.Function<TestJobBase, java.util.Date> STARTED = newcom.google.common.base.Function<TestJobBase, java.util.Date>() {
publicjava.util.Dateapply(TestJobBasevalue) {
returnvalue.getStarted();
}
};
privatedoublenumber;
@javax.xml.bind.annotation.XmlTransientpublicdoublegetNumber() {
returnnumber;
}
publicvoidsetNumber(doublenumber) {
doubleoldValue = this.number;
this.number = number;
propertyChangeSupport.firePropertyChange("number", oldValue, number);
}
publicTestJobnumber(doublefluentValue) {
setNumber(fluentValue);
return (TestJob) this;
}
publicfinalstaticcom.google.common.base.Function<TestJobBase, java.lang.Double> NUMBER = newcom.google.common.base.Function<TestJobBase, java.lang.Double>() {
publicjava.lang.Doubleapply(TestJobBasevalue) {
returnvalue.getNumber();
}
};
protectedfinaljava.beans.PropertyChangeSupportpropertyChangeSupport = newjava.beans.PropertyChangeSupport(this);
publicvoidaddPropertyChangeListener(java.beans.PropertyChangeListenerlistener) {
propertyChangeSupport.addPropertyChangeListener(listener);
}
publicvoidaddPropertyChangeListener(StringpropertyName, java.beans.PropertyChangeListenerlistener) {
propertyChangeSupport.addPropertyChangeListener(propertyName, listener);
}
publicvoidremovePropertyChangeListener(java.beans.PropertyChangeListenerlistener) {
propertyChangeSupport.removePropertyChangeListener(listener);
}
publicvoidremovePropertyChangeListener(StringpropertyName, java.beans.PropertyChangeListenerlistener) {
propertyChangeSupport.removePropertyChangeListener(propertyName, listener);
}
publicTestJoblisten(java.beans.PropertyChangeListenerlistener) {
addPropertyChangeListener(listener);
return (TestJob) this;
}
publicTestJoblisten(StringpropertyName, java.beans.PropertyChangeListenerlistener) {
addPropertyChangeListener(propertyName, listener);
return (TestJob) this;
}
} // end of class definition```