I can't quite comprehend how to best go about implementing a Builder pattern for the following generics hierarchy.
Base class,
#lombok.Data
public class Node<T> {
private T data;
private String source;
}
Child class,
#lombok.Data
public class MyNode extends Node<MyNode> {
private String firstDummy;
private String secondDummy;
}
Is there anyway to apply an anonymous builder class to the parent and extend it in the child class ?
Updated
If i have an anonymous builder like so for the Parent,
public class Node<T> {
private T data;
private final String source;
public static abstract class Builder<S extends Node> {
private String source;
public Builder<S> withSource(String source) {
this.source = source;
return this;
}
public abstract S build();
}
public static Builder<?> builder() {
return new Builder<Node>() {
#Override
public Node build() {
return new Node(this);
}
};
}
protected Node(Builder<?> builder) {
this.source = builder.source;
}
}
How do I then implement the builder for T in Node class ?
If you want to practice im implementing builders, then yes, you can implement them. The hint of #nixgadget is good.
But if you just need a builder, add an annotation #Builder and Lombok will do that for you.
Related
I'm trying to implement a BuilderPattern, where a subclass must extend a superclass.
Superclass:
#Getter
public abstract class CommonValidatorConfig<VC extends CommonValidatorConfig<VC>> {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<VC, VCB extends CommonValidatorConfigBuilder<VC, VCB>> {
protected boolean canBeNull;
protected boolean canBeEmpty;
#SuppressWarnings("unchecked")
public VCB canBeNull(boolean canBeNull) {
this.canBeNull = canBeNull;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB canBeEmpty(boolean canBeEmpty) {
this.canBeEmpty = canBeEmpty;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return (VCB) this;
}
public abstract VC build();
}
}
Subclass:
#Builder
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public class StringValidatorConfig extends CommonValidatorConfig<StringValidatorConfig> {
public static class StringValidatorConfigBuilder extends CommonValidatorConfigBuilder<StringValidatorConfig, StringValidatorConfigBuilder> {
#Override
public StringValidatorConfig build() {
return new StringValidatorConfig(false, false); // ERROR
}
}
}
The AllArgsConstructor AccessLevel is set to PRIVATE because I want to create a new instance using only Builders.
I was expecting an AllArgsConstructor for StringValidatorConfig with two variables (canBeNull and canBeEmpty), but the AllArgsConstructor takes no arguments for the constructor.
this means that the variables of the CommonValidatorConfig are not inherited.
Any help, also tutorials/docs/references or improvements of code are welcomed.
#SuperBuilder will do all the work for you:
#Getter
#SuperBuilder
public abstract class CommonValidatorConfig {
private boolean canBeNull;
private boolean canBeEmpty;
}
#SuperBuilder
public class StringValidatorConfig extends CommonValidatorConfig {
}
That's it.
If you need to add a custom method inside your builder, you can do so by adding the class header of the (abstract) builder class and add your method. Lombok will add all the rest of its methods. I suggest you copy the class header from the delombok output (run java -jar path/to/lombok.jar delombok -p path/to/ClassWithSuperBuilder.java).
#Getter
#SuperBuilder
public abstract class CommonValidatorConfig {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<C extends CommonValidatorConfig, B extends CommonValidatorConfig.CommonValidatorConfigBuilder<C, B>> {
public B setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return self();
}
}
}
The "experimental" status of #SuperBuilder just means it may not receive bugfixes as quickly as stable features. Furthermore, there are plans to promote #SuperBuilder to stable.
The code Lombok generates is completely type-safe, there are no unchecked type conversions. So even if you later decide that you don't want #SuperBuilder anymore, you can simply de-lombok it. The resulting code will be better than your manual solution.
I'm not sure if this is the best way, but I solved in this way:
Superclass:
I added an AllArgsConstructor with AccessLevel PROTECTED.
#Getter
#AllArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class CommonValidatorConfig<VC extends CommonValidatorConfig<VC>> {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<VC, VCB extends CommonValidatorConfigBuilder<VC, VCB>> {
protected boolean canBeNull;
protected boolean canBeEmpty;
#SuppressWarnings("unchecked")
public VCB canBeNull(boolean canBeNull) {
this.canBeNull = canBeNull;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB canBeEmpty(boolean canBeEmpty) {
this.canBeEmpty = canBeEmpty;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return (VCB) this;
}
public abstract VC build();
}
}
Subclass:
1 - Removed lombok AllArgsConstructor.
2 - Declared the AllArgsConstructor and passed the variables to superclass constructor.
3 - Access to superclass variables using super keyword.
#Builder
public class StringValidatorConfig extends CommonValidatorConfig<StringValidatorConfig> {
private StringValidatorConfig(boolean canBeNull, boolean canBeEmpty) {
super(canBeNull, canBeEmpty);
}
public static class StringValidatorConfigBuilder extends CommonValidatorConfigBuilder<StringValidatorConfig, StringValidatorConfigBuilder> {
#Override
public StringValidatorConfig build() {
return new StringValidatorConfig(super.canBeNull, super.canBeEmpty);
}
}
}
I have a base class and a derived class, both designed to be immutable (ctor and getters omitted):
public class PageQuery<T> {
private final T queryFilter;
private PageCond pageCond; // pagination parameter
// E withPageCond(PageCond newPageCond) {
// return a brand new copy of `this` with `pageCond` replaced with `newPageCond`
// that can be reused across class hierarchy
// }
}
public class PageSortQuery<T> extends PageQuery<T>{
private final SortCond sortCond; // sorting parameter
}
How to add a method that returns defensive copy of this to the base class so that all classes in this hierarchy can benefit from it? Is there a way to accomplish it without clone()?
I don't know if you mean something like this, in this case if you call the withFilter method the origin would not become changed.
#AllArgsConstructor
public class Query <T> {
#Getter
private final String name;
#Getter
private final Predicate<T> filter;
public Query<T> withFilter(Predicate<T> filter){
return new DelegatingQuery<T>(this){
#Override
public Predicate<T> getFilter() {
return Query.this.filter;
}
};
}
static class DelegatingQuery<T> extends Query<T>{
#Delegate
private final Query<T> query;
public DelegatingQuery(Query<T> query) {
super(query.name,query.filter);
this.query = query;
}
}
}
I want to get rid of the following code duplication within the MyFacadeBean. Consider the following situation:
public class FacadeBean implements Facade {
#EJB
private CrudService crudService;
#Inject
private FirstAssembler firstAssembler;
#Inject
private SecondAssembler secondAssembler;
#Inject
private ThirdAssembler thridAssembler;
#Inject
private FourthAssembler fourthAssembler;
#Override
public void save(FirstValue value) {
FirstEntity entity = this.firstAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
#Override
public void save(SecondValue value) {
SecondEntity entity = this.secondAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
#Override
public void save(ThirdValue value) {
ThirdEntity entity = this.thirdAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
#Override
public void save(FourthValue value) {
FourthEntity entity = this.fourthAssembler.transformToEntity(value);
this.crudService.persist(entity);
}
}
public interface MyFacade {
void save(FirstValue value);
void save(SecondValue value);
}
With the CrudService:
public interface CrudService {
void persist(Object entity);
}
#Stateless
#Local(CrudService.class)
#TransactionAttribute(TransactionAttributeType.MANDATORY)
public class CrudServiceBean implements CrudService {
public static final String PERSISTENCE_UNIT_NAME = "my_persistence_unit";
private EntityManager entityManager;
#PersistenceContext(unitName = PERSISTENCE_UNIT_NAME)
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
#Override
public void persist(Object entity) {
this.entityManager.persist(entity);
}
}
With the following assemblers:
public class FirstAssembler extends AbstractAssembler<FirstEntity> {
public FirstEntity transformToEntity(FirstValue value) {
if (value == null)
return null;
FirstEntity entity = new FirstEntity();
transformAbstractValueToAbstractObject(value, entity);
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
}
public class SecondAssembler extends AbstractAssembler<SecondEntity> {
public SecondEntity transformToEntity(SecondValue value) {
if (value == null)
return null;
SecondEntity entity = new SecondEntity();
transformAbstractValueToAbstractObject(value, entity);
entity.setTransactionType(value.getTransactionType());
entity.setValueDate(value.getValueDate());
return entity;
}
}
public abstract class AbstractAssembler<T extends AbstractEntity> {
protected void transformAbstractValueToAbstractObject(AbstractValue value, T object) {
object.setUniqueId(value.getUniqueId());
object.setNominalAmountValue(value.getNominalAmountValue());
}
}
With the following entities:
#Entity
public class FirstEntity extends AbstractEntity {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
private Long id;
#Column(name = "START_DATE")
#Temporal(TemporalType.DATE)
private Date startDate;
#Column(name = "FIXED_RATE")
#Digits(integer = 1, fraction = 10)
private BigDecimal fixedRate;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public BigDecimal getFixedRate() {
return fixedRate;
}
public void setFixedRate(BigDecimal fixedRate) {
this.fixedRate = fixedRate;
}
}
#Entity
public class SecondEntity extends AbstractEntity {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
private Long id;
#Column(name = "VALUE_DATE")
#Temporal(TemporalType.DATE)
private Date valueDate;
#Column(name = "TRANSACTION_TYPE")
#Enumerated(EnumType.STRING)
private TransactionType transactionType;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getValueDate() {
return valueDate;
}
public void setValueDate(Date valueDate) {
this.valueDate = valueDate;
}
public TransactionType getTransactionType() {
return transactionType;
}
public void setTransactionType(TransactionType transactionType) {
this.transactionType = transactionType;
}
}
#MappedSuperclass
public abstract class AbstractEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "TRANSACTION_NOM_AMOUNT_VALUE")
#Digits(integer = 18, fraction = 5)
#Min(0)
private BigDecimal nominalAmountValue;
public BigDecimal getNominalAmountValue() {
return nominalAmountValue;
}
public void setNominalAmountValue(BigDecimal nominalAmountValue) {
this.nominalAmountValue = nominalAmountValue;
}
}
I tried the following approach:
public class FacadeBean implements Facade {
#Inject
private Assembler assembler;
#Inject
private AssemblerFactory assemblerFactory;
#Override
public <T extends AbstractValue> void save(T value) {
Assembler assembler = assemblerFactory.createAssembler(value);
AbstractEntity entity = assembler.transformToEntity(value);
this.crudService.persist(entity);
}
}
Problems are the AssemblerFactoryImpl and the AssemblerImpl in which I have to do instanceOf checks and castings...
Another idea would be to let the value know which transformer to use (or how to transform). But I want the value to be "dumb".
#Glenn Lane
public AbstractValue save(AbstractValue value) {
AbstractAssembler<AbstractValue, AbstractEntity> assembler = new FirstAssembler();
AbstractEntity entity = assembler.transformToEntity(value);
AbstractValue result = assembler.transformToValue(entity);
return result;
}
does not work, because of
Type mismatch: cannot convert from FirstAssembler to AbstractAssembler
I'm posting this as a separate answer, since I don't really think there's anything wrong with having a save method for every AbstractValue type.
First we'll establish your base value class for this example. I'm using an interface just so we don't muddy the waters. Your AbstractValue interface:
public interface AbstractValue
{
int getUniqueId();
double getNominalValue();
<T> T accept(AbstractValueVisitor<T> visitor);
}
And the "visitor interface":
public interface AbstractValueVisitor<T>
{
T visit(FirstValue value);
T visit(SecondValue value);
T visit(ThirdValue value);
T visit(FourthValue value);
}
I know you don't want intelligence baked into AbstractValue, but we are going to add one specification... that all concrete implementations of AbstractValue (all four) implement the accept method exactly this way:
#Override
public <T> T accept(AbstractValueVisitor<T> visitor)
{
return visitor.visit(this);
}
So that method is implemented four times: in all four value classes, exactly the same way. Because the visitor interface is aware of all concrete implementations, the appropriate method will be called for each particular value type. All three of these parts put together is the "visitor pattern".
Now we'll make an entity factory. Its job is to create the appropriate AbstractEntity when provided an AbstractValue:
public class AbstractEntityFactory
implements AbstractValueVisitor<AbstractEntity>
{
private static final AbstractEntityFactory INSTANCE;
static
{
INSTANCE = new AbstractEntityFactory();
}
// Singleton pattern
private AbstractEntityFactory()
{
}
public static AbstractEntity create(AbstractValue value)
{
if (value == null)
{
return null;
}
AbstractEntity e = value.accept(INSTANCE);
e.setNominalValue(value.getNominalValue());
e.setUniqueId(value.getUniqueId());
return e;
}
#Override
public AbstractEntity visit(FirstValue value)
{
FirstEntity entity = new FirstEntity();
// Set all properties specific to FirstEntity
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
#Override
public AbstractEntity visit(SecondValue value)
{
SecondEntity entity = new SecondEntity();
// Set all properties specific to SecondEntity
entity.setTransactionType(value.getTransactionType());
entity.setValueDate(value.getValueDate());
return entity;
}
#Override
public AbstractEntity visit(ThirdValue value)
{
ThirdEntity entity = new ThirdEntity();
// Set all properties specific to ThirdEntity
return entity;
}
#Override
public AbstractEntity visit(FourthValue value)
{
FourthEntity entity = new FourthEntity();
// Set all properties specific to FourthEntity
return entity;
}
}
Now your facade implementation takes an AbstractValue, and you got that one save method you're looking for:
public class FacadeBean implements Facade
{
#EJB
private CrudService crudService;
#Override
public void save(AbstractValue value)
{
AbstractEntity entity = AbstractEntityFactory.create(value);
crudService.persist(entity);
}
}
Because your AbstractValue now follows the visitor pattern, you can do all sorts of polymorphic behavior. Such as:
public class AbstractValuePrinter implements AbstractValueVisitor<Void>
{
private final Appendable out;
public AbstractValuePrinter(Appendable out)
{
this.out = out;
}
private void print(String s)
{
try
{
out.append(s);
out.append('\n');
}
catch (IOException e)
{
throw new IllegalStateException(e);
}
}
#Override
public Void visit(FirstValue value)
{
print("I'm a FirstValue!");
print("Being a FirstValue is groovy!");
return null;
}
#Override
public Void visit(SecondValue value)
{
print("I'm a SecondValue!");
print("Being a SecondValue is awesome!");
return null;
}
#Override
public Void visit(ThirdValue value)
{
print("I'm a ThirdValue!");
print("Meh.");
return null;
}
#Override
public Void visit(FourthValue value)
{
print("I'm a ThirdValue!");
print("Derp.");
return null;
}
}
In this example, this visitor isn't returning anything... it's "doing" something, so we'll just set the return value as Void, since it's non-instantiatable. Then you print the value simply:
// (value must not be null)
value.accept(new AbstractValuePrinter(System.out));
Finally, the coolest part of the visitor pattern (in my opinion): you add FifthValue. You add the new method to your visitor interface:
T visit(FifthValue value);
And suddenly, you can't compile. You must address the lack of this handling in two places: AbstractEntityFactory and AbstractValuePrinter. Which is great, because you should consider it in those places. Doing class comparisons (with either instanceof or rinde's solution of a class-to-factory map) is likely to "miss" the new value type, and now you have runtime bugs... especially if you're doing 100 different things with these value types.
Anyhoo, I didn't want to get into this, but there you go :)
Use a generic method with a bound type parameter in order to spare yourself the repetition:
public <T extends AbstractValue> T save(T value) {...}
Within the method body, you'll be able to reference the argument value with all methods pertaining to AbstractValue.
Notes
Since your save methods seem to be overrides in this example, you might need to change the design of the parent class or interface too.
You could also use a generic class to start with (instead of a generic method in a non-necessarily generic class), depending on your use case.
I think a problem in your code is that the generic type of AbstractAssembler is that of the output of the transform method, not the input. If you change it as follows:
public abstract class AbstractAssembler<T extends AbstractValue> {
protected void transformAbstractValueToAbstractObject(AbstractEntity entity, T value) {
entity.setUniqueId(value.getUniqueId());
entity.setNominalAmountValue(value.getNominalAmountValue());
}
public abstract AbstractEntity transformToEntity(T value);
}
Then you can change the FacadeBean to the following.
public class FacadeBean {
#EJB
private CrudService crudService;
final Map<Class<?>, AbstractAssembler<?>> knownAssemblers;
FacadeBean() {
knownAssemblers = new LinkedHashMap<>();
knownAssemblers.put(FirstValue.class, new FirstAssembler());
knownAssemblers.put(SecondValue.class, new SecondAssembler());
// add more assemblers here
}
public <T extends AbstractValue> void save(T value, Class<T> type) {
#SuppressWarnings("unchecked") // safe cast
final AbstractAssembler<T> assembler =
(AbstractAssembler<T>) knownAssemblers.get(type);
final AbstractEntity entity = assembler.transformToEntity(value);
this.crudService.persist(entity);
}
}
Notice that I changed the signature of the save(..) method such that we have the type of the object that needs to be saved. With this type we can simply lookup the right assembler that should be used. And because the assembler is now generic on its input type, we can do a safe cast (be careful to keep your map consistent).
This implementation avoids duplication of code as you only need one save method. The use of the instanceof operator is prevented by changing the generic type of AbstractAssembler and storing all assemblers in a map.
The assemblers can look like this:
public class FirstAssembler extends AbstractAssembler<FirstValue> {
#Override
public FirstEntity transformToEntity(FirstValue value) {
final FirstEntity entity = new FirstEntity();
// do transformational stuff
super.transformAbstractValueToAbstractObject(entity, value);
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
}
public class SecondAssembler extends AbstractAssembler<SecondValue> {
#Override
public SecondEntity transformToEntity(SecondValue value) {
final SecondEntity entity = new SecondEntity();
// do transformational stuff
super.transformAbstractValueToAbstractObject(entity, value);
return entity;
}
}
Note: I'm not familiar with Java beans so you probably have to adapt the code a little if you want to use the #Injected assemblers instead of calling the constructors directly.
You're getting close to gold-plating here, but there is a bit of reduction you can do, specifically the null-check and calling the common field-setting method from each extension.
public abstract class AbstractAssembler<V extends AbstractValue, E extends AbstractEntity>
{
public final E transformToEntity(V value)
{
if (value == null)
{
return null;
}
E entity = createEntity(value);
entity.setUniqueId(value.getUniqueId());
entity.setNominalAmountValue(value.getNominalAmountValue());
return entity;
}
/**
* #return
* Appropriate entity object, with the fields not common to all AbstractEntity
* already set
*/
protected abstract E createEntity(V value);
}
And then the extended assembler:
public class FirstAssembler extends AbstractAssembler<FirstValue, FirstEntity>
{
#Override
protected FirstEntity createEntity(FirstValue value)
{
FirstEntity entity = new FirstEntity();
entity.setFixedRate(value.getFixedRate());
entity.setStartDate(value.getStartDate());
return entity;
}
}
If you really want a single factory class to handle all your values/entities, I would look into the visitor pattern, enhanced with a generic type parameter on the visitor interface (and the entity/value accept methods return a type based on the visiting interface). I won't show an example here simply because I don't think it's warranted in your case.
You can have one save method from the point of view of the classes that save those values, but you still have to implement three individual save methods.
Implement a class with all three save methods. For example:
public class ValuePersister {
#Inject
private Assembler1 assembler1;
#Inject
private Assembler2 assembler2;
#Inject
private Assembler3 assembler3;
public Value1 save(Value1 value1, CrudService crudService) {
Entity1 entity1 = assembler1.transformToObject(value1);
crudService.persist(entity1);
return assembler1.transformToValue(entity1);
}
public Value2 save(Value2 value2, CrudService crudService) {
Entity2 entity2 = assembler2.transformToObject(value2);
crudService.persist(entity2);
return assembler2.transformToValue(entity2);
}
public Value3 save(Value3 value3, CrudService crudService) {
Entity3 entity3 = assembler3.transformToObject(value3);
crudService.persist(entity3);
return assembler3.transformToValue(entity3);
}
}
Add an abstract method to AbstractValue:
public abstract AbstractValue save(ValuePersister valuePersister, CrudService crudService);
Implement that method in each class that extends AbstractValue:
#Override
public AbstractValue save(ValuePersister valuePersister, CrudService crudService) {
return valuePersister.save(this, crudService);
}
Inject ValuePersister and implement your original generic save method:
#Inject
private ValuePersister valuePersister;
#Override
public AbstractValue save(AbstractValue value) {
return value.save(valuePersister, crudService)
}
I have recently started to read Effective Java by Joshua Bloch. I found the idea of the Builder pattern [Item 2 in the book] really interesting. I tried to implement it in my project but there were compilation errors. Following is in essence what I was trying to do:
The class with multiple attributes and its builder class:
public class NutritionalFacts {
private int sodium;
private int fat;
private int carbo;
public class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder(int s) {
this.sodium = s;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
Class where I try to use the above class:
public class Main {
public static void main(String args[]) {
NutritionalFacts n =
new NutritionalFacts.Builder(10).carbo(23).fat(1).build();
}
}
I am getting the following compiler error:
an enclosing instance that contains
effectivejava.BuilderPattern.NutritionalFacts.Builder
is required
NutritionalFacts n = new
NutritionalFacts.Builder(10).carbo(23).fat(1).build();
I do not understand what the message means. Please explain. The above code is similar to the example suggested by Bloch in his book.
Make the builder a static class. Then it will work. If it is non-static, it would require an instance of its owning class - and the point is not to have an instance of it, and even to forbid making instances without the builder.
public class NutritionFacts {
public static class Builder {
}
}
Reference: Nested classes
You should make the Builder class as static and also you should make the fields final and have getters to get those values. Don't provide setters to those values. In this way your class will be perfectly immutable.
public class NutritionalFacts {
private final int sodium;
private final int fat;
private final int carbo;
public int getSodium(){
return sodium;
}
public int getFat(){
return fat;
}
public int getCarbo(){
return carbo;
}
public static class Builder {
private int sodium;
private int fat;
private int carbo;
public Builder sodium(int s) {
this.sodium = s;
return this;
}
public Builder fat(int f) {
this.fat = f;
return this;
}
public Builder carbo(int c) {
this.carbo = c;
return this;
}
public NutritionalFacts build() {
return new NutritionalFacts(this);
}
}
private NutritionalFacts(Builder b) {
this.sodium = b.sodium;
this.fat = b.fat;
this.carbo = b.carbo;
}
}
And now you can set the properties as follows:
NutritionalFacts n = new NutritionalFacts.Builder().sodium(10).carbo(15).
fat(5).build();
To generate an inner builder in Intellij IDEA, check out this plugin: https://github.com/analytically/innerbuilder
You are trying access a non-static class in a static way. Change Builder to static class Builder and it should work.
The example usage you give fails because there is no instance of Builder present. A static class for all practical purposes is always instantiated. If you don't make it static, you'd need to say:
Widget = new Widget.Builder(10).setparm1(1).setparm2(3).build();
Because you would need to construct a new Builder every time.
You need to declare the Builder inner class as static.
Consult some documentation for both non-static inner classes and static inner classes.
Basically the non-static inner classes instances cannot exist without attached outer class instance.
Once you've got an idea, in practice, you may find lombok's #Builder much more convenient.
#Builder lets you automatically produce the code required to have your class be instantiable with code such as:
Person.builder()
.name("Adam Savage")
.city("San Francisco")
.job("Mythbusters")
.job("Unchained Reaction")
.build();
Official documentation: https://www.projectlombok.org/features/Builder
This mean that you cant create enclose type. This mean that first you have to cerate a instance of "parent" class and then from this instance you can create nested class instances.
NutritionalFacts n = new NutritionalFacts()
Builder b = new n.Builder(10).carbo(23).fat(1).build();
Nested Classes
The Builder class should be static. I don't have time right now to actually test the code beyond that, but if it doesn't work let me know and I'll take another look.
I personally prefer to use the other approach, when you have 2 different classes. So you don't need any static class. This is basically to avoid write Class.Builder when you has to create a new instance.
public class Person {
private String attr1;
private String attr2;
private String attr3;
// package access
Person(PersonBuilder builder) {
this.attr1 = builder.getAttr1();
// ...
}
// ...
// getters and setters
}
public class PersonBuilder (
private String attr1;
private String attr2;
private String attr3;
// constructor with required attribute
public PersonBuilder(String attr1) {
this.attr1 = attr1;
}
public PersonBuilder setAttr2(String attr2) {
this.attr2 = attr2;
return this;
}
public PersonBuilder setAttr3(String attr3) {
this.attr3 = attr3;
return this;
}
public Person build() {
return new Person(this);
}
// ....
}
So, you can use your builder like this:
Person person = new PersonBuilder("attr1")
.setAttr2("attr2")
.build();
As many already stated here you need to make the class static.
Just small addition - if you want, there is a bit different way without static one.
Consider this. Implementing a builder by declaring something like withProperty(value) type setters inside the class and make them return a reference to itself. In this approach, you have a single and an elegant class which is a thread safe and concise.
Consider this:
public class DataObject {
private String first;
private String second;
private String third;
public String getFirst(){
return first;
}
public void setFirst(String first){
this.first = first;
}
...
public DataObject withFirst(String first){
this.first = first;
return this;
}
public DataObject withSecond(String second){
this.second = second;
return this;
}
public DataObject withThird(String third){
this.third = third;
return this;
}
}
DataObject dataObject = new DataObject()
.withFirst("first data")
.withSecond("second data")
.withThird("third data");
Check it out for more Java Builder examples.
You need to change Builder class to static class Builder. Then it will work fine.
The other solutions double the memory allocation to instantiate the object. The following solution does not have that problem.
public class NutritionalFacts{
private int sodium;
private int fat;
private int carbo;
private NutritionalFacts(){}
public int getSodium(){ return sodium;}
public int getFat(){ return fat;}
public int getCarbo(){ return carbo;}
public static class Builder{
private NutritionalFacts nutrionalFacts;
public Builder(){
nutrionalFacts = new NutritionalFacts();
}
public Builder sodium(int s){
nutrionalFacts.sodium = s;
return this;
}
public Builder fat(int f){
nutrionalFacts.fat = f;
return this;
}
public Builder carbo(int c){
nutrionalFacts.carbo = c;
return this;
}
public NutritionalFacts build(){
return nutrionalFacts;
}
}
}
I have several interfaces all with the same constants - ID and ROOT. I also have a method into which I pass an object that will be an implementation of one of these interfaces.
How can I dynamically retrieve the value of the constant depending on the class passed in - i.e. I want to do something like the following:
public void indexRootNode(Node node, Class rootNodeClass)
{
indexService.index(node, rootNodeClass.getConstant('ID'),
rootNodeClass.getConstant('ROOT'));
}
In PHP this is easy, but is this possible in Java? I've seen this problem solved using accessors on the constant, but I want to retrieve the constant directly. Annotations won't help me here either.
Thanks
This can be achieved using reflection (also see corresponding javadoc).
public void indexRootNode(Node node, Class rootNodeClass)
{
Field idField = rootNodeClass.getField("ID");
Object idValue = idField.get(null);
Field rootField = rootNodeClass.getField("ROOT");
Object rootValue = rootField.get(null);
indexService.index(node, idValue, rootValue);
}
Maybe you may additionaly have to cast the values to the corresponding type.
Please read chapter 19 use interfaces only to define types from Joshua Bloch's Effective Java (in fact, please read the entire book)
Constants do not belong in an interface!!! Constants should be tied to implementing classes, not interfaces.
Either use non-constant methods:
// the implementing classes can define these values
// and internally use constants if they wish to
public interface BaseInterface{
String id(); // or getId()
String root(); // or getRoot()
}
public interface MyInterface1 extends BaseInterface{
void myMethodA();
}
public interface MyInterface2 extends BaseInterface{
void myMethodB();
}
or use an enum to tie things together:
public enum Helper{
ITEM1(MyInterface1.class, "foo", "bar"),
ITEM2(MyInterface2.class, "foo2", "baz"),
;
public static String getId(final Class<? extends BaseInterface> clazz){
return fromInterfaceClass(clazz).getId();
}
public static String getRoot(final Class<? extends BaseInterface> clazz){
return fromInterfaceClass(clazz).getRoot();
}
private static Helper fromInterfaceClass(final Class<? extends BaseInterface> clazz){
Helper result = null;
for(final Helper candidate : values()){
if(candidate.clazz.isAssignableFrom(clazz)){
result = candidate;
}
}
return result;
}
private final Class<? extends BaseInterface> clazz;
private final String root;
private final String id;
private Helper(final Class<? extends BaseInterface> clazz,
final String root,
final String id){
this.clazz = clazz;
this.root = root;
this.id = id;
};
public String getId(){
return this.id;
}
public String getRoot(){
return this.root;
}
}
// use it like this
String root = Helper.fromInterfaceClass(MyInterface1.class).getRoot();