7

We can always have multiple classes inside a .java file. Considering encapsulation and that each class consists of multiple lines of code it always made sense to have 1 class (don't talk about nested classes) inside 1 .java file.

Now that records come into play and they can be as little as 1 line of code. Does it make sense to encapsulate multiple records inside the same .java class?

For example we could have

DTO.java file which would contain

record Employees(List<Employee> employees) { }  //This is just a wrapper class that we normally need in order to return a list of objects in rest web services
record Employee(String name, Integer age, List<Attribute> attributes){ }
record Attribute(String name, String value) { }

If no record has the public access modifier then we are allowed to contain all of them in a file with the name DTO.java

As I view it, it does not seem very good to have 3 .java files with only 1 line of code inside each one.

However we can still face issues like these described here multiple classes inside same java file

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
Panagiotis Bougioukos
  • 15,955
  • 2
  • 30
  • 47

3 Answers3

12

Right now there is no official way to do it.
As a workaround you could create an empty interface and put all your records inside, for example if your controller is CompanyController, I would create an interface called CompanyPort with all dto records inside

CompanyPort.java:

public interface CompanyPort {
      record Employees(List<Employee> employees) { } 
      record Employee(String name, Integer age, List<Attribute> attributes){ }
      record Attribute(String name, String value) { }
}

Hope that would help

Hamdi
  • 361
  • 3
  • 6
7

The facts that have not changed are:

  1. You can not have more than one public class in a single .java file. However, you can have as many non-public classes in the same .java file as you wish.
  2. The name of the .java file must be the same as the public class in it.
  3. If none of the classes in a .java file is public, it can have any name.

Note: Since you have mentioned another answer in your question, I have included those classes as well in my demo just in case they can be helpful to join the dots.

Attribute.java:

import java.util.List;

public record Attribute(String name, String value) { }
record Employee(String name, Integer age, List<Attribute> attributes){ }
record Employees(List<Employee> employees) { }

Bar.java:

public class Bar {
    
}
class Baz {
    public void hello(){
        System.out.println("Hello");
    }
}

Foo.java:

import java.util.List;

public class Foo {
    public static void main(String[] args) {
        Attribute attr1 = new Attribute("A", "X");
        Attribute attr2 = new Attribute("B", "Y");
        System.out.println(attr1);

        Employee e1 = new Employee("James", 23, List.of(attr1, attr2));
        System.out.println(e1);
        Employee e2 = new Employee("Boug", 21, List.of(attr2));

        Employees emps = new Employees(List.of(e1, e2));
        System.out.println(emps);

        Baz baz = new Baz();
        baz.hello();
    }
}

Terminal commands:

[~/Desktop/Record]: javac Bar.java
[~/Desktop/Record]: javac Attribute.java 
[~/Desktop/Record]: javac Foo.java 
[~/Desktop/Record]: java Foo
Attribute[name=A, value=X]
Employee[name=James, age=23, attributes=[Attribute[name=A, value=X], Attribute[name=B, value=Y]]]
Employees[employees=[Employee[name=James, age=23, attributes=[Attribute[name=A, value=X], Attribute[name=B, value=Y]]], Employee[name=Boug, age=21, attributes=[Attribute[name=B, value=Y]]]]]
Hello
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • 1
    4. You can get problems with compilers/build tools or IDEs when they don’t know where to search for a particular class when the class whose name determined the file name has not been referenced – Holger Mar 22 '21 at 09:47
1

In this case, since the records are related, you can do the equivalent thing to having static inner classes in a standard class - i.e.:

public record Employees(List<Employee> employees) {
    public record Employee(String name, Integer age, List<Attribute> attributes) {}
    public record Attribute(String name, String value) {}
}

The consumer will, as they did before records, access the sub-records as

Employees.Employee employee;
Employees.Attribute attribute;
Milad
  • 836
  • 7
  • 13