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
What is the most idiomatic way to go about this?
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.
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.