Search code examples
javarestsdkaccess-modifiersidioms

most idiomatic way to structure a client side REST library?


I'm writing a REST API. I want to separate my classes into neat little folders but I still want them all to have package access to eachother.

The reason for this is that I want one class only to have public access.

Example:

+---com.mysuper.sdk
|
+------ models
|          |---- Model.java
+------ controllers
|          |---- Controller.java
|
+---PublicAPI.java
  1. PublicAPI.java needs to be able to see all the models and controllers.
  2. The controllers need to be able to see the models.
  3. Anyone who uses my library should only be able to see PublicAPI.java

What is the most idiomatic way to go about this?


Solution

  • The most idiomatic way to express what your code, meaning Java convention, would be to have three packages for your code: com.mysuper.sdk, com.mysuper.sdk.models & com.mysuper.sdk.controllers.

    That being said, nowhere in the Java Language Specification (September 2015) does it require package names to reflect the underlying folder structure. Take example below:

    ./src/com/mysuper/sdk/PublicAPI.java

    package com.mysuper.sdk;
    
    // Public class.
    public class PublicAPI {
        // Main method.
        public static void main(String... args) {
            int[] numbers = new int[args.length];
    
            for (int i = 0; i < args.length; i++) {
                numbers[i] = Integer.parseInt(args[i]);
            }
    
            System.out.println(new Controller().translateNumbers(numbers));
        }
    }
    

    ./src/com/mysuper/sdk/controllers/Controller.java

    package com.mysuper.sdk;
    
    // Package protected class.
    class Controller {
        // Private model.
        private Model model = new Model();
    
        // Package protected method.
        String translateNumbers(int... numbers) {
            String translation = "";
            for (int number : numbers) {
                translation = translation + model.get(number) + " ";
            }
            return translation;
        }
    }
    

    ./src/com/mysuper/sdk/models/Model.java

    package com.mysuper.sdk;
    
    // Package protected class.
    class Model {
        // Private database.
        private String[] database = {"zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
    
        // Package protected method.
        String get(int number) {
            if (number < 0 || number > 9) {
                throw new NumberFormatException("Number " + number + " is not between 0 and 9.");
            } else {
                return database[number];
            }
        }
    }
    

    Compiling this code with javac will not throw any syntax errors, because the code is syntactically correct. Try it yourself:

    javac -d bin ./src/com/mysuper/sdk/PublicAPI.java \
    ./src/com/mysuper/sdk/controllers/Controller.java \
    ./src/com/mysuper/sdk/models/Model.java
    
    java -cp ./bin com.mysuper.sdk.PublicAPI 0 1 2 3 4 5 6 7 8 9
    

    You should get output along the lines of:

    zero one two three four five six seven eight nine
    

    All of this having been said, there are a couple of reasons why you should stick to organising your classes into separate packages.

    1. Most IDEs will treat packages that do not correlate with your folder structure as fatal compilation errors.
    2. This is convention as it aids in readability of code, guiding other developers to the folders containing your classes.
    3. It will encourage your to better encapsulate your code to separate responsibilities of your code modules.

    If you wanted to get a similar result while also following Java best practice, I would encourage you to follow Michael Aaron Safyan's advice and familiarise yourself with Factory Method pattern to abstract the implementation of your SDK from your public interface.

    How best to implement said pattern for your project is better left for another question.