Building fluent APIs in Java to build testdata for database

166 views Asked by At

Im trying to make a small DSL in Java that I can use to populate testdata in a database. The language I would like to use is as follows.

createRowInTableA().
   createRowInTableB().
createRowInTableA().
   createRowInTableB().
      createRowInTableC().
end();

The order the tables are created is important, for example tableB depends on tableA and tableC depends on tableA and tableB. Therefore I want to make it so that the option to create tableB only is available directly after tableA is created etc. I have started to create the interfaces describing the DSL but I don't know how I should actually implement the interfaces inorder to make the type of nested behavior I'm looking for. This is what the interfaces looks like.

public interface End {
    public void sendTestData(); 
}

public interface TableA extends End {
   public Builder createRowInTableA();
}

public interface TableB extends TableA {
   public Builder createRowInTableB();
}

public interface TableC extends TableB {
   public Builder createRowInTableC();
}

However when I start implementing this language using builder pattern to create a fluent API the hierarchy I want goes away.

public class DBBuilder implements TableC {
   static class Builder {
      public Builder createRowInTableA(){...}
      public Builder createRowInTableB(){...}
      public Builder createRowInTableC(){...}
   }
}
2

There are 2 answers

0
frhack On

You can use a set of interfaces and class adapters:

public interface canCreateTableAIf{
   public DBBuilderB createRowInTableA()
}  

public interface canCreateTableBIf{
   public DBBuilderC createRowInTableB()
}  

public interface canCreateTableCIf{
   public DBBuilderD createRowInTableC()
}  


public class canCreateTableA implements canCreateTableAIf (){
  public DBBuilderB createRowInTableA(){
    ...
  }
}

public class canCreateTableB implements canCreateTableBIf (){
  public DBBuilderC createRowInTableB(){
    ...
  }
}

public class DBBuilderRoot extends canCreateTableA {
}


public class DBBuilderB  extends canCreateTableB {
}

public class DBBuilderBCD  extends canCreateTableB,canCreateTablec,canCreateTableD {
}
0
Peter Paul Kiefer On

This is not so complicated. But I would check if there is a better way than using fluent Builders. Java 8 for example offers closures. Hier is my suggestion. I've not compiled and tested it. The idea should work but there might be syntax errors.

public class ABuilder 
{
    private BBuilder subBuilder;

    public ABuilder()
    {
      subBuilder = new BBuilder(this);
    }

    public BBuilder createRowForA()
    {
       // your code
       return this.subBuilder;
    }

    public void end()
    {
      // send test data
    }
}

x

public class BBuilder 
{
    private ABuilder parentBuilder;
    private CBuilder subBuilder;

    public BBuilder( ABuilder parentBuilder )
    {
      this.parentBuilder = parentBuilder;
      this.subBuilder = new CBuilder(this);
    }

    public CBuilder createRowForB()
    {
       // your code
       return this.subBuilder;
    }

    public ABuilder end()
    {
      return this.parentBuilder;
    }
}

x

public class CBuilder 
{
    private BBuilder parentBuilder;

    public CBuilder( BBuilder parentBuilder )
    {
      this.parentBuilder = parentBuilder;
    }

    public CBuilder createRowForC()
    {
       // your code

       // I Assume you want to be able to write more than 1 C-row
       return this;
    }

    public BBuilder end()
    {
      return this.parentBuilder;
    }
}

Then you can do:

(new ABuilder())
    .createRowForA()
      .createRowForB()
        .createRowForC()
        .end()
      .end()
     .end();

(new ABuilder())
    .createRowForA()
      .createRowForB()
        .end()
      .createRowForB()
        .createRowForC()
        .end()
       .end()
     .end();

I'm sure you see more exmples. ;-)