Tyler Garavaglia
Tyler Garavaglia

Reputation: 83

Java - Using Generics to Create a Fluent Interface

In my current assignment, I have to build a new SchemaArtifact object filled with recursive Field objects (both custom classes) for a test case. I also need to do this using a fluent interface. The problem is that my build() function (pops up one level in the tree) should either return the root SchemaArtifact if the calling field is at the top level or return its parent if it is a child field. I know this might sound confusing, so hopefully some example code can clear it up:

public class SchemaHelper{
    public SchemaArtifact makeSchema(){
        return new SchemaArtifact()
            .addField(new Field("FirstName"))
                .addField(new Field("Nickname")).build()
                .build()
            .addField(new Field("LastName")).build();
    }
}

public class SchemaArtifact{
    private Map<String, Field> fields = new Map();

    public addField(Field f){
        this.fields.put(field.id, f);
        return f;
    }
}

public class Field{
    public String id;
    private Map<String, Field> fields = new Map(); //children
    private Field parent; //null if parent is just the main schema
    private SchemaArtifact schema; //schema that this Field belongs to

    public Field(String id){
        this.id = id;
    }

    public Field addField(Field f){
        this.fields.put(field.id, f);
        return f;
    }

    public <T> T build(){
        if(this.parent != null){
            return (T)this.parent;
        }else{
            return (T)this.schema;
        }
    }
}

As you can see, I tried using generics to return multiple types, but I get "The method addField(Field) is undefined for the type Object" when I try adding more than one Field at once. I also tried using a wrapper interface, which required needless casting later; and separate buildToSchema()/buildToField() methods, which works, but makes creating multiple schemas down the line more confusing.

With all that said, is there a way for me to get the singular build() method to return both a SchemaArtifact and a Field?

Thank you,
Tyler

Upvotes: 0

Views: 278

Answers (1)

WilQu
WilQu

Reputation: 7393

The return type of build() must be known at compile time. In this case, the class of the returned object depends on a runtime condition, so it can't be known at compile time.

Two possibilities :

  • You know when to expect a Field or a SchemaArtifact. In this case you should use two separates methods and use them where appropriate.
  • You don't know what type to expect. In this case you should use an interface.

You could also to this :

Field field = new SchemaArtifact()
        .addField(new Field("FirstName"))
            .addField(new Field("Nickname")).build();
SchemaArtifactschema = field.build();

This will force the compiler to infer the right types, but it's the same as using two different methods, just less type safe (there will be a ClassCastException if you use the wrong type).

Upvotes: 1

Related Questions