I'm busy implementing Step Builders into a Java application and I've written some horrendous code. I'm quite certain I'm missing a necessary step.
For an example, I'll use the buildable class Machine.java
public class Machine {
private String type;;
private boolean mobile;
private final String mobileType;
public Machine(MachineBuilder builder) {
this.type = builder.type;
this.mobile = builder.mobile;
this.mobileType = builder.mobileType;
}
public String getType() { return this.type; }
public boolean getMobile() { return this.mobile; }
public String getMobileType() { return this.mobileType; }
}
And the step builder for it as MachineBuilder.java
public class MachineBuilder {
public String type;
public boolean mobile;
public String mobileType;
public MachineBuilder() { }
// initialize builder
public Builder start() {
return new Builder();
}
// interfaces
public interface iType {
iBuild withType(String type);
}
public interface iMobileType {
iBuild withMobileType(String mobileType);
}
public interface iBuild {
iMobileType withMobile();
iBuild withMobileType(String mobileType);
Machine build();
}
// subclass to return
public static class Builder extends MachineBuilder implements iType, iMobileType, iBuild {
public iBuild withType(String type) {
super.type = type; return this;
}
public iMobileType withMobile() {
super.mobile = true; return this;
}
public iBuild withMobileType(String mobileType) {
super.mobileType = mobileType; return this;
}
public Machine build() {
return new Machine(this);
}
}
}
The intention is to have type as a required step, then mobile as optional but if mobile is used then mobileType must be used as well.
It's only half working though
// fine
Machine car = new MachineBuilder()
.start().withType("car").withMobile().withMobileType("driving").build();
System.out.println(car.getType() + ":" + car.getMobile() + ":" + car.getMobileType());
// fine
Machine washingMachine = new MachineBuilder()
.start().withType("washingMachine").build();
System.out.println(washingMachine.getType() + ":" + washingMachine.getMobile() + ":" + washingMachine.getMobileType());
// corrupt (no type)
Machine boat = new MachineBuilder()
.start().withMobile().withMobileType("sailing").build();
System.out.println(boat.getType() + ":" + boat.getMobile() + ":" + boat.getMobileType());
// corrupt (no anything)
Machine bicycle = new MachineBuilder()
.start().build();
System.out.println(bicycle.getType() + ":" + bicycle.getMobile() + ":" + bicycle.getMobileType());
I had to initialize the builder object with the method start but this is not implementing any of the interfaces so just calling start then build will corrupt the object. Similarly calling the optional method for mobile allows it to bypass the type.
Is it possible to force flow direction from the start without using a start method at all? I feel like I am missing something very stupid.
PS. sorry for slapping so much code into the question I just wanted to illustrate the issue as best as I can
Thrill to answer this question. I try to rewrite your code. Just reorganize it following Step Builder Pattern's strategy.
Add no description here, hope you can easily understand the code.
class Machine {
private String type;
private boolean isMobile;
private String mobileType;
public static TypeStep builder(){
return new MachineBuilder();
}
public interface TypeStep{
IsMobileStep withType(String type);
}
public interface IsMobileStep{
MobileTypeStep withMobile(boolean isMobile);
}
public interface MobileTypeStep{
Build withMobileType(String mobileType);
}
public interface Build{
Machine build();
}
public static class MachineBuilder implements TypeStep, IsMobileStep, MobileTypeStep, Build {
private String type;
private boolean isMobile;
private String mobileType;
#Override
public IsMobileStep withType(String type) {
this.type = type;
return this;
}
#Override
public MobileTypeStep withMobile(boolean isMobile) {
this.isMobile = isMobile;
return this;
}
#Override
public Build withMobileType(String mobileType) {
this.mobileType = mobileType;
return this;
}
#Override
public Machine build() {
return new Machine(this);
}
}
private Machine(MachineBuilder machineBuilder) {
this.type = machineBuilder.type;
this.isMobile = machineBuilder.isMobile;
this.mobileType = machineBuilder.mobileType;
}
public String getType() {
return type;
}
public boolean isMobile() {
return isMobile;
}
public String getMobileType() {
return mobileType;
}
}
Test run:
public class Main{
public static void main(String[] args) {
Machine car = Machine.builder().withType("car").withMobile(true).withMobileType("driving").build();
System.out.println("Model 1:"+ car.getType() +":"+ car.isMobile()+":"+car.getMobileType());
Machine boat = Machine.builder().withType("boat").withMobile(true).withMobileType("driving").build();
System.out.println("Model 2:"+ boat.getType() +":"+ boat.isMobile()+":"+boat.getMobileType());
}
}
Output:
Model 1:car:true:driving
Model 2:boat:true:driving
For better readability: Github Repo Step Builder
I think your builder implementation is very difficult and not very correct.
The typical builder should have private constructors, initial methods, field setters and build methods. I would do so:
public class MachineBuilder {
public String type;
public boolean mobile;
public String mobileType;
private MachineBuilder (final String type, final boolean mobile, final String mobileType) {
this.type = type;
this.mobile = mobile;
this.mobileType = mobileType;
}
private MachineBuilder(){
}
public MachineBuilder setType(final String source) {
this.type = source;
return this;
}
public MachineBuilder setMobile(final boolean source) {
this.mobile = source;
return this;
}
public MachineBuilder setMobileType(final String source) {
this.mobileType = source;
return this;
}
public static MachineBuilder init() {
return new MachineBuilder();
}
public static MachineBuilder init(final String type, final boolean mobile, final String mobileType) {
return new MachineBuilder(type, mobile, mobileType);
}
public MachineBuilder build() {
return Machine(this.type, this.mobile, this.mobileType);
}
}
Related
This is a generic class with bound type Player.
public class Team<T extends Player> implements Comparable<Team<T>> {
private String name;
private int played=0;
private int won=0;
private int lost=0;
private int tide=0;
private ArrayList<T> members = new ArrayList<>();
public Team(String name) {
this.name = name;
}
public String getName() {
return name;
}
public int getWon() {
return won;
}
public boolean addPlayer(T player){
if(members.contains(player)){
System.out.println(player.getName() + " is already on this team" );
return false;
}else{
members.add(player);
System.out.println(player.getName()+" picked for team "+this.name);
return true;
}
}
public int numPlayer(){
return this.members.size();
}
}
This is a generic class with bound Type as Team.
public class League<T extends Team>{
public String name;
private ArrayList<T> league = new ArrayList<>();
public League(String name) {
this.name = name;
}
public boolean addTeam(T team){
if(league.contains(team)){
System.out.println("It is already exist");
return false;
}else{
league.add(team);
return true;
}
}
public void showLeagueTable(){
Collections.sort(league);
for(T t:league){
System.out.println(t.getName()+" : "+t.ranking());
}
}
}
I don't know how to create an object for the League class, literally not able to figure out how to mention type. I've tried several ways, but none of them worked for me. Could you guys help me with this code?
is this the right way to create builder pattern in java, if not what could be possible changes.
tried with static class
public class Multiverse {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
public Boolean getHumanExistence() {
return humanExistence;
}
private Multiverse() {
throw new IllegalStateException("Can`t create object from constructor: try using builder");
}
private Multiverse(UUID universeId, String universeName, String universeType, Boolean humanExistence) {
super();
this.universeId = universeId;
this.universeName = universeName;
this.universeType = universeType;
this.humanExistence = humanExistence;
}
public static class MultiverseBuilder{
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
public MultiverseBuilder makeUUId(UUID uuid) {
this.universeId=uuid;
return this;
}
public MultiverseBuilder createUniverse(String univ) {
this.universeName=univ;
return this;
}
public MultiverseBuilder setUniverseType(String universeType ) {
this.universeType=universeType;
return this;
}
public MultiverseBuilder isHumanExists(Boolean humanExistence) {
this.humanExistence=humanExistence;
return this;
}
public Multiverse build() {
return new Multiverse(universeId,universeName,universeType,humanExistence);
}
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
}
Junit5 test
public class AssertionsTest6 {
private static Logger logger=Logger.getLogger(AssertionsTest6.class.getName());
Multiverse multiverse;
#BeforeEach
void init(){
multiverse=new Multiverse.MultiverseBuilder()
.makeUUId(UUID.randomUUID())
.createUniverse("Earth")
.setUniverseType("Big Bang")
.isHumanExists(true)
.build();
}
#Test
#DisplayName("Builder Testing")
void TestBuilder() {
assertEquals("Big Bang", multiverse.getUniverseType(), "test failed");
logger.info("Builder testing");
}
}
blocked reflection to make object directly from Multiverse class by doing this
private Multiverse() {
throw new IllegalStateException("Can`t create object from constructor: try using builder");
}
expected and actual are same. but not sure is this the best way to achieve objective. please correct or suggest me on this, [ expert advice required ]
Design considerations:
force usage of builder (no direct instance creation allowed)?
immutability (what happens when invoking setters on builder after an instance has been created)?
reusability: allow builder to create multiple instances?
Example for a non-reusable builder which can be used to create exactly one instance, which is effectively immutable:
public class Multiverse {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
private Multiverse() {
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
public Boolean getHumanExistence() {
return humanExistence;
}
public static Builder aMultiverse() {
return new Builder();
}
public static class Builder {
private final Multiverse instance = new Multiverse();
private boolean consumed;
private Builder set(Consumer<Multiverse> access) {
if (consumed) {
throw new IllegalStateException("already consumed");
}
access.accept(instance);
return this;
}
public Builder universeId(UUID universeId) {
return set(x -> x.universeId = universeId);
}
public Builder universeName(String universeName) {
return set(x -> x.universeName = universeName);
}
public Builder universeType(String universeType) {
return set(x -> x.universeType = universeType);
}
public Builder humanExistence(Boolean humanExistence) {
return set(x -> x.humanExistence = humanExistence);
}
public Multiverse build() {
consumed = true;
return instance;
}
}
}
The aMultiVerse() naming convention for accessing the builder allows static import of the builder factory method without clashing with other builder factory methods:
Multiverse multiverse = aMultiverse()
.universeId(UUID.randomUUID())
.universeName("Earth")
.universeType("Big Bang")
.humanExistence(true)
.build();
Some notes about your approach:
I don't think that it makes any sense to 'block' users from creating an instance via reflection. Since you defined a constructor there is no no-arg constructor anyways. Thus instances can only be created by passing a builder.
I like to pass the builder instance to the constructor. This way you will have readable code even if the class has a lot of fields.
I like to call my builder just Builder. It's a nested class und you will probably always write Multiverse.Builder.
I like the actual class to have a factory method for the builder so I can just write Multiverse.builder() and start populating the fields.
The methods of the builder class should have a consistent naming scheme.
This is how my builders usually look like:
public class Multiverse {
private final UUID universeId;
private final String universeName;
private final String universeType;
private final Boolean humanExistence;
private Multiverse(Builder builder) {
this.universeId = builder.universeId;
this.universeName = builder.universeName;
this.universeType = builder.universeType;
this.humanExistence = builder.humanExistence;
}
public static Builder builder() {
return new Builder();
}
public UUID getUniverseId() {
return universeId;
}
public String getUniverseName() {
return universeName;
}
public String getUniverseType() {
return universeType;
}
public Boolean getHumanExistence() {
return humanExistence;
}
public Builder toBuilder() {
return new Builder(this);
}
public static class Builder {
private UUID universeId;
private String universeName;
private String universeType;
private Boolean humanExistence;
private Builder() {}
private Builder(Multiverse multiverse) {
this.universeId = multiverse.universeId;
this.universeName = multiverse.universeName;
this.universeType = multiverse.universeType;
this.humanExistence = multiverse.humanExistence;
}
public Builder withUniverseId(UUID universeId) {
this.universeId = universeId;
return this;
}
public Builder withUniverseName(String universeName) {
this.universeName = universeName;
return this;
}
public Builder withUniverseType(String universeType) {
this.universeType = universeType;
return this;
}
public Builder withHumanExistence(Boolean humanExistence) {
this.humanExistence = humanExistence;
return this;
}
public Multiverse build() {
return new Multiverse(this);
}
}
}
Creating multiverses works like this:
Multiverse multiverse1 = Multiverse.builder()
.withUniverseId(UUID.fromString("550e8400-e29b-11d4-a716-446655440000"))
.withUniverseName("my first multiverse")
.withUniverseType("type a")
.withHumanExistence(true)
.build();
If you decide to edit this multiverse later, you can do it like this:
Multiverse multiverse2 = multiverse1.toBuilder()
.withUniverseId(UUID.fromString("759e947a-7492-af67-87bd-87de9e7f5e95"))
.withUniverseName("my second multiverse")
.build();
This would fulfill the following assertions:
assert multiverse1.getUniverseId().equals("550e8400-e29b-11d4-a716-446655440000");
assert multiverse1.getUniverseName().equals("my first multiverse");
assert multiverse1.getUniverseType.equals("type a");
assert multiverse1.getHumanExistence == true;
assert multiverse2.getUniverseId().equals("759e947a-7492-af67-87bd-87de9e7f5e95");
assert multiverse2.getUniverseName().equals("my second multiverse");
assert multiverse2.getUniverseType.equals("type a");
assert multiverse2.getHumanExistence == true;
this is the final solution i think , Thank you #stevecross
public final class BootServer { // step #1 make class and fields final
private final Integer port;
private final String serverName;
private final String serverType;
private final String listenerType;
private BootServer(Builder builder) {// step #2 create private constructor
this.port = builder.port;
this.serverName = builder.serverName;
this.serverType = builder.serverType;
this.listenerType=builder.listenerType;
}
public static Builder builder() {//Step#3 create static builder method to return Builder
return new Builder();
}
public static final class Builder {//Step#4 create public static builder class
private Integer port;
private String serverName;
private String serverType;
private String listenerType;
private Builder(){
}
public BootServer build() {//Step#5 create build method to return BootServer Object with this object
return new BootServer(this);
}
public Builder addServerPort(Integer port) {//Step#6 finally create all build method to set values to main class
this.port=port;
return this;
}
public Builder addServerName(String name) {
this.serverName=name;
return this;
}
public Builder setServerType(String serverType) {
this.serverType=serverType;
return this;
}
public Builder setListenerType(String listenerType) {
this.listenerType=listenerType;
return this;
}
}
#Override
public String toString() {
return "BootServer [port=" + port + ", serverName=" + serverName + ", serverType=" + serverType
+ ", listenerType=" + listenerType + "]";
}
}
In my project, we have to create a system where we create an object Facility and we have to run inspections and maintenance on it to check if it's working. We created a Facility object and then we created a state machine that changes the state of the Facility to resting, working, maintenance, or working.
Here is the SuperFacility class:
import java.util.Map;
public interface SuperFacility {
public void setName(String name);
public void setAddress(String address);
public void setDescription(String description);
public void setRefNumber(int refNumber);
public void setCapacity(int capacity);
public void setCost(double cost);
public void setProblemRate(int problemRate);
public String getName();
public String getAddress();
public String getDescription();
public int getRefNumber();
public int getCapacity();
public double getCost();
public int getProblemRate();
public void oxygenator(boolean oxygenator);
public void nuclearReactor(boolean nuclearReactor);
public void innerAirlocks(boolean innerAirlocks);
public void externalAirlocks(boolean externalAirlocks);
public void comms(boolean comms);
public void waterMaking(boolean waterMaking);
public void startMachines();
public Map getMap();
public void getFacilityStatus();
public void getFacilityStatus(Map<String, Boolean> map);
}
Here is the Facility class:
import java.util.*;
public class Facility extends StateMachine implements SuperFacility {
public String name, address, description;
public int refNumber, capacity, problemRate;
private double cost;
private Map<String, Boolean> map = new HashMap<String, Boolean>();
private boolean[] machines = new boolean[6];
private boolean oxygenator, innerAirlocks, externalAirlocks,
comms, nuclearReactor, waterMaking;
private final int numberOfMachines = 6; // Number of Machines inside Facility
// Setters
public void setName(String name){
this.name = name;
}
public void setAddress(String address){
this.address = address;
}
public void setDescription(String description){
this.description = description;
}
public void setRefNumber(int refNumber){
this.refNumber = refNumber;
}
public void setCapacity(int capacity){
this.capacity = capacity;
}
public void setCost(double cost){
this.cost = cost;
}
public void setProblemRate(int problemRate){
this.problemRate = problemRate;
}
// Getters
public String getName(){
return name;
}
public String getAddress(){
return address;
}
public String getDescription(){
return description;
}
public int getRefNumber(){
return refNumber;
}
public int getCapacity(){
return capacity;
}
public double getCost(){
return cost;
}
public int getProblemRate(){
return problemRate;
}
public void oxygenator(boolean oxygenator){
this.oxygenator = oxygenator;
}
public void nuclearReactor(boolean nuclearReactor){
this.nuclearReactor = nuclearReactor;
}
public void innerAirlocks(boolean innerAirlocks){
this.innerAirlocks = innerAirlocks;
}
public void externalAirlocks(boolean externalAirlocks){
this.externalAirlocks = externalAirlocks;
}
public void comms(boolean comms){
this.comms = comms;
}
public void waterMaking(boolean waterMaking){
this.waterMaking = waterMaking;
}
public boolean[] getMachines(){
machines[0] = oxygenator;
machines[1] = nuclearReactor;
machines[2] = innerAirlocks;
machines[3] = externalAirlocks;
machines[4] = comms;
machines[5] = waterMaking;
return machines;
}
// Set machines to false
public void breakMachines(){
oxygenator(false);
nuclearReactor(false);
innerAirlocks(false);
externalAirlocks(false);
comms(false);
waterMaking(false);
map.clear();
initializeMap(map);
}
public void startMachines(){
// Set all of the booleans from this Facility to true;
// This booleans are what we call "the machines from the Facility"
oxygenator(true);
nuclearReactor(true);
innerAirlocks(true);
externalAirlocks(true);
comms(true);
waterMaking(true);
map.clear();
initializeMap(map);
}
public void initializeMap(Map<String, Boolean> map){
this.map.put("Oxygenator", oxygenator);
this.map.put("Inner Airlocks", innerAirlocks);
this.map.put("External Airlocks", externalAirlocks);
this.map.put("Nuclear Reactor", nuclearReactor);
this.map.put("Comms", comms);
this.map.put("WaterMaking", waterMaking);
}
public Map<String, Boolean> getMap(){
return map;
}
public void getFacilityStatus(){ // The status of the map in this object
for (Map.Entry<String, Boolean> i: map.entrySet()){
System.out.println(i.getKey() + ": " + i.getValue());
}
}
public void getFacilityStatus(Map<String, Boolean> map){ // The status of any Facility map
for (Map.Entry<String, Boolean> i: map.entrySet()){
System.out.println(i.getKey() + ": " + i.getValue());
}
}
}
Here is the StateMachine class:
public class StateMachine {
public State state = State.RESTING;
enum State {
WORKING, RESTING, MAINTENANCE, BROKEN
}
public State getFacilityState(){
return state;
}
public void setStateWorking(Facility fac){
fac.state = State.WORKING;
}
public void setStateResting(Facility fac){
fac.state = State.RESTING;
}
public void setStateMaintenance(Facility fac){
fac.state = State.MAINTENANCE;
}
public void setStateBroken(Facility fac) { fac.state = State.BROKEN;}
public State getState(){
return state;
}
}
In my Inspection class, I have two methods that have to check the state of the Facility to see if it's working, but I am having trouble with my if statement:
import java.util.*;
public class Inspection {
private Facility fac;
public boolean isBroken(){
if (fac.state == State.BROKEN)
return true;
else
return false;
}
public void makeMaintenanceRequest(Control c){
if (fac.state == State.BROKEN){
c.scheduleMaintenance(fac);
}
}
I want the methods to be able to compare the current state of a Facility to the Broken state. How should I compare the states? I keep getting the "cannot find symbol" error for State.BROKEN
Although I cannot understand very well what you're trying to do, I can tell you the Inspection class might already work as you'd like.
I see you commented out the constructor, why? It was okay to inject a Facility instance inside Inspection. However, you should accept a StateMachine instead.
public class Inspection {
private final StateMachine stateMachine;
public Inspection(final StateMachine stateMachine) {
this.stateMachine = stateMachine;
}
...
}
Then, inside your Inspection#isBroken method
public boolean isBroken() {
return this.stateMachine.getFacilityState() == State.BROKEN; // "this" not necessary
}
As Facility extends StateMachine, it exposes a getFacilityState() method.
And because Facility extends StateMachine, Inspection is able to accept it.
final Facility facility = new Facility(...);
final Inspection inspection = new Inspection(facility);
final boolean isBroken = inspection.isBroken();
A simple solution would be to replace State.BROKEN with StateMachine.State.BROKEN
public boolean isBroken(){
if (fac.state == StateMachine.State.BROKEN)
return true;
else
return false;
}
I'm familiar with using the builder pattern with generics and subclassing, but I can't see how to make it work with a non-trivial tree of subclasses (i.e. C extends B extends A). Here's a simple example of what I'm trying to do:
class A {
private final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() { return value; }
public static class ABuilder<T extends ABuilder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T) this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static BBuilder builder() {
return new BBuilder();
}
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() { return name; }
public static class BBuilder<U extends BBuilder<U>> extends ABuilder<BBuilder<U>> {
private String name;
public U withName(String name) {
this.name = name;
return (U) this;
}
public B build() {
return new B(this);
}
}
}
Everything is fine if I declare BBuilder without the generic type:
public static class BBuilder extends ABuilder<BBuilder>
Since I want BBuilder to be extended by a CBuilder, I'm trying to use the same sort of Curiously Recurring Template Pattern as ABuilder. But like this, the compiler sees BBuilder.withValue() as returning an ABuilder, not a BBuilder as I want. This:
B b = builder.withValue(1)
.withName("X")
.build();
doesn't compile. Can anyone see what I'm doing wrong here, I've been going round trying different patterns of generics but can't get it to work.
Thanks to anyone who has any advice.
It seems that your mistake only with declaring correct parameter:
class A {
private final int value;
public static <T extends Builder<T>> T builderA() {
return (T)new Builder<>();
}
protected A(Builder<? extends Builder<?>> builder) {
value = builder.value;
}
public static class Builder<T extends Builder<T>> {
private int value;
public T withValue(int value) {
this.value = value;
return (T)this;
}
public A build() {
return new A(this);
}
}
}
class B extends A {
private final String name;
public static <T extends Builder<T>> T builderB() {
return (T)new Builder<>();
}
protected B(Builder<? extends Builder<?>> builder) {
super(builder);
name = builder.name;
}
public static class Builder<T extends Builder<T>> extends A.Builder<T> {
private String name;
public Builder<T> withName(String name) {
this.name = name;
return this;
}
public B build() {
return new B(this);
}
}
}
Client code:
A a = A.builder().withValue(1).build();
B b = B.builder().withValue(2).withName("xx").build();
Are you certain you need generics? This hierarchy seems to work fine without generics.
static class A {
protected final int value;
protected A(ABuilder builder) {
this.value = builder.value;
}
public int getValue() {
return value;
}
#Override
public String toString() {
return "A{" +
"value=" + value +
'}';
}
public static ABuilder builder() {
return new ABuilder();
}
public static class ABuilder {
protected int value;
public ABuilder withValue(int value) {
this.value = value;
return this;
}
public A build() {
return new A(this);
}
}
}
static class B extends A {
protected final String name;
protected B(BBuilder builder) {
super(builder);
this.name = builder.name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "B{" +
"value=" + value +
", name='" + name + '\'' +
'}';
}
public static BBuilder builder() {
return new BBuilder();
}
public static class BBuilder extends ABuilder {
private String name;
public BBuilder withName(String name) {
this.name = name;
return this;
}
#Override
public BBuilder withValue(int value) {
this.value = value * 2;
return this;
}
public B build() {
return new B(this);
}
}
}
static class C extends B {
private final String otherName;
protected C(CBuilder builder) {
super(builder);
this.otherName = builder.otherName;
}
public String getName() {
return otherName;
}
#Override
public String toString() {
return "C{" +
"value=" + value +
", name='" + name + '\'' +
", otherName='" + otherName + '\'' +
'}';
}
public static CBuilder builder() {
return new CBuilder();
}
public static class CBuilder extends BBuilder {
private String otherName;
public CBuilder withName(String name) {
this.otherName = name;
return this;
}
public C build() {
return new C(this);
}
}
}
public void test() {
A a = A.builder().withValue(10).build();
B b = B.builder().withValue(10).withName("B").build();
C c = C.builder().withName("C").build();
System.out.println("a = "+a);
System.out.println("b = "+b);
System.out.println("c = "+c);
}
I am trying to assign the value returned by some function to a field in the deserialized class of json.
FileInfo.java
public class FileInfo {
#SerializedName("Name")
private String mName;
#SerializedName("Url")
private String mUri;
#SerializedName("Size")
private Integer mSize;
#SerializedName("ModTime")
private Long mModifiedTime;
private FileType mType;
#SerializedName("Children")
private ArrayList<FileInfo> mChildren = new ArrayList<>();
public ArrayList<FileInfo> getChildren() {
return mChildren;
}
public long getModifiedTime() {
return mModifiedTime;
}
public String getName() {
return mName;
}
public Integer getSize() {
return mSize;
}
public String getUrl() {
return mUri;
}
public FileType getType() {
return mType;
}
public void setChildren(ArrayList<FileInfo> mChildren) {
this.mChildren = mChildren;
}
public void setModifiedTime(long mModifiedTime) {
this.mModifiedTime = mModifiedTime;
}
public void setName(String mName) {
this.mName = mName;
}
public void setSize(Integer mSize) {
this.mSize = mSize;
}
public void setType(FileType mType) {
this.mType = mType;
}
public void setUri(String mUri) {
this.mUri = mUri;
}
#Override
public String toString() {
return FileInfo.class.toString();
}
public FileInfo() {
}
}
The mType needs to be assigned to foo(mName). I looked up custom deserializers and instance creators but none of those helped. I also thought of TypeAdapters which i feel defeats the purpose of keeping deserialization(using GSON) simple.
This is a sample JSON string that will be deserialized.
[
{
"Name":"Airport",
"Url":"http://192.168.2.2/api/sites/Baltimore%20Airport/Airport",
"Size":0,
"ModTime":"2015-12-02T14:19:17.29824-05:00",
"Children":null
}
]
P.S. I'm not sure if this should be done during deserialization but trying anyways. Also please let me know of alternative ways to achieve this.