Skip to content

How can I provide this sort of String builder class?

I like to have a Drive class where all files and folders for a project are managed.

My first attempt was pretty easy like a lot of functions (most of them with arguments).

Now I try to make it more fancy because it became more and more annoying to have a lot of functions, in which the desired one can be found. To not have an XY-problem here, I start with my dream. I like to construct the Drive class in a way, so that it is super easy to find a certain file or folder.

If you look in the main function, I can find every needed file by writing a point and look which subclasses/methods are proposed to continue, till I find it and add .str to it. At every point, only the subclasses/methods will be proposed which makes sense at this point. It almost works! It is more complicated to write and maintain as the first approach, but If I use it very often, it could be worth it.

I can:

  1. go into subfolders
  2. go into subfolders with name inside the argument

But there is an error if I define a fixed-name-subfolder of a fluid-name-folder like in the code below.

Now my questions:

  1. how can I change the code so the main Function doesn’t show this error?
  2. would you recommend a completely different approach to the “make it easy to find strings inside a huge list of strings via making collections inside collections… of strings”-problem?
package utilities;

public class Drive_draft {
    private static final String fs = System.getProperty("file.separator");
    
    public static final String str = System.getProperty("user.home").concat(fs);
    
    public static class IeCreation {
        public static final String str = Drive_draft.str.concat(".meetings").concat(fs);
        
        public static class Abstract {
            public static final String str = IeCreation.str.concat("Abstracts").concat(fs);
        }
        
        public static class Meeting {
            public static final String str = IeCreation.str.concat("Ueberordnungen").concat(fs);
        }
    }
    
    public static class MetsSIPs {
        public static final String str = Drive_draft.str.concat("workspace").concat(fs).concat("metsSIPs").concat(fs);
        
        public static class preSIPs {
            public static final String str = MetsSIPs.str.concat("preSIPs").concat(fs);
        }
        
        public static class RosettaInstance {           
            private static class MaterialflowId {
                public static String str;
                
                private static class ProducerId {
                    public static String str;
                    
                    private static class Abstract {
                        public static String str;
                        
                        public static class Mets {
                            public static final String str = Abstract.str.concat("content").concat(fs).concat("ie1.xml");
                        }
                    }
                    
                    private static class Meeting {
                        public static String str;
                    }
                    
                    public static Abstract Abstract (String value) {
                        Abstract ret = new Abstract();
                        ProducerId.Abstract.str = str.concat(value).concat(fs);
                        return ret;
                    }
                    
                    public static Meeting Meeting (String value) {
                        Meeting ret = new Meeting();
                        ProducerId.Meeting.str = str.concat(value).concat(fs);
                        return ret;
                    }
                }
                
                public static ProducerId ProducerId (String value) {
                    ProducerId ret = new ProducerId();
                    MaterialflowId.ProducerId.str = str.concat(value).concat(fs);
                    return ret;
                }
            }
            
            public static MaterialflowId MaterialflowId (String value) {
                MaterialflowId ret = new MaterialflowId();
                MaterialflowId.str = str.concat(value).concat(fs);
                return ret;
            }
        }
        
        public static class Dev extends RosettaInstance {
            public static final String str = MetsSIPs.str.concat("dev").concat(fs);
        }
        
        public static class Test extends RosettaInstance {
            public static final String str = MetsSIPs.str.concat("test").concat(fs);
        }
        
        public static class Prod extends RosettaInstance{
            public static final String str = MetsSIPs.str.concat("prod").concat(fs);
        }
    }
    
    @SuppressWarnings("static-access")
    public static void main(String[] args) {
        System.out.println(Drive_draft.MetsSIPs.Dev.str);
        System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").str);
        System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("2").str);
        System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").str);
        System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Abstract("est").str);
        System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Meeting("oast").str);
        System.out.println(Drive_draft.MetsSIPs.Dev.MaterialflowId("1").ProducerId("t").Abstract("est").Mets.str); //Error: Mets cannot be resolved or is not a field
    }
}

Answer

You can encode your “directory” structure with interfaces, with each interface declaring what the user can do next. Then the implementation can use a StringBuilder to just append the appropriate snippets and keep returning this.

// PathBuilderInterfaces.java
public class PathBuilderInterfaces {
  public interface Buildable {
    String build();
  }

  public interface Drive extends Buildable {
    IeCreation ieCreation();
    MetsSIPs metsSIPs();
  }

  public interface IeCreation extends Buildable {
    String ieCreationAbstract();
    String meeting();
  }

  public interface MetsSIPs extends Buildable {
    RosettaInstance dev();
    RosettaInstance test();
    RosettaInstance prod();
  }

  public interface RosettaInstance extends Buildable {
    MaterialFlowId materialFlowId(String value);
  }

  public interface MaterialFlowId extends Buildable {
    ProducerId producerId(String value);
  }

  public interface ProducerId extends Buildable {
    Abstract producerIdAbstract(String value);
    String meeting(String value);
  }

  public interface Abstract extends Buildable {
    String mets();
  }
}
// PathBuilder.java
import static com.example.somepackage.PathBuilderInterfaces.*;

public class PathBuilder implements Drive, IeCreation, MetsSIPs, RosettaInstance, MaterialFlowId, ProducerId, Abstract{
  private StringBuilder builder = new StringBuilder(str);
  private static final String fs = System.getProperty("file.separator");
  public static final String str = System.getProperty("user.home").concat(fs);

  public static Drive drive() {
    return new PathBuilder();
  }

  @Override
  public String build() {
    return builder.toString();
  }

  @Override
  public IeCreation ieCreation() {
    builder.append(".meetings").append(fs);
    return this;
  }

  @Override
  public MetsSIPs metsSIPs() {
    builder.append("workspace").append(fs).append("metsSIPs").append(fs);
    return this;
  }

  @Override
  public RosettaInstance dev() {
    builder.append("dev").append(fs);
    return this;
  }

  @Override
  public RosettaInstance test() {
    builder.append("test").append(fs);
    return this;
  }

  @Override
  public RosettaInstance prod() {
    builder.append("prod").append(fs);
    return this;
  }

  @Override
  public MaterialFlowId materialFlowId(String value) {
    builder.append(value).append(fs);
    return this;
  }

  @Override
  public ProducerId producerId(String value) {
    builder.append(value).append(fs);
    return this;
  }

  @Override
  public Abstract producerIdAbstract(String value) {
    builder.append(value).append(fs);
    return this;
  }

  @Override
  public String meeting(String value) {
    builder.append(value).append(fs);
    return build();
  }

  @Override
  public String mets() {
    builder.append("content").append(fs).append("ie1.xml");
    return build();
  }

  @Override
  public String ieCreationAbstract() {
    builder.append("Abstracts").append(fs);
    return build();
  }

  @Override
  public String meeting() {
    builder.append("Ueberordnungen").append(fs);
    return build();
  }
}

Usage:

// in a main method somewhere
System.out.println(
    PathBuilder.drive()
        .metsSIPs()
        .dev()
        .materialFlowId("1")
        .producerId("t")
        .producerIdAbstract("est")
        .mets());