Flexible generic data structure for storing immutable constant values can enhance enums for more complex usages.
The constant-containers library offers a robust mechanism for defining and working with immutable, constant values in a type-safe way. This library enhances the capabilities of enums and enum-like structures allowing for more complex relationships and operations.
- Enum and Enum-like Containers: Supports enum and enum-like structures to hold constants, improving upon traditional enums by allowing more complex data structures and relationships.
- Immutable Constants: Encourages the use of immutable constant values, ensuring thread safety and consistency.
- Type-safe Operations: Provides type-safe operations on the constants and containers, reducing the risk of runtime errors.
- Flexible Relationships: Allows defining one-to-one, one-to-many, and many-to-many relationships among constants.
- Utility Methods: Offers utility methods for matching, retrieving, and operating on constants and their relationships, such as anyValue, anyRelationValue, getEnumByValue, and match.
- Support for Anonymous and Inner Classes: Enables defining constants within anonymous and inner classes, though with some limitations.
Add constants-containers library dependency to your project. The latest version is 1.2.0.
Maven:
<dependency>
<groupId>io.github.mrsaraira</groupId>
<artifactId>constant-containers</artifactId>
<version>1.2.0</version>
</dependency>
Gradle:
dependencies {
implementation 'io.github.mrsaraira:constant-containers:1.2.0'
}
import io.github.mrsaraira.constants.*;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum Role implements EnumRelationConstantContainer<String, String, Role> {
ADMIN(Constants.of("Admin", "CREATE", "READ", "UPDATE", "DELETE")),
EDITOR(Constants.of("Editor", "CREATE", "READ", "UPDATE")),
VIEWER(Constants.of("Viewer", "READ"));
private final RelationConstant<String, String> constant;
}
This enum-like structure uses the library to define a Role with related permissions. Each Role is a constant that holds a relationship with multiple permissions.
You can now use the defined Role container to perform various operations, such as checking permissions, finding a role by its name, or listing all permissions of a role.
boolean hasDeletePermission = Constants.anyRelationValue("DELETE", Role.ADMIN);
System.out.println("Does ADMIN have DELETE permission? " + hasDeletePermission);
// Get a Role by its name
Optional<Role> optionalRole = Constants.getEnumByValue("Editor", Role.class);
optionalRole.ifPresent(role -> System.out.println("Found role: " + role.getConstant().getKey().getValue()));
// List all permissions of the VIEWER role
Constant<String>[] viewerPermissions = Role.VIEWER.getConstant().getRelations();
System.out.println("VIEWER permissions: " + Arrays.toString(viewerPermissions));
List<String> relationValues = Constants.getRelationValues(Role.VIEWER.getConstant());
System.out.println("VIEWER permissions values: " + relationValues);
Output:
Does ADMIN have DELETE permission? true
Found role: Editor
VIEWER permissions: [ConstantImpl(value=READ)]
VIEWER permissions: [READ]
This example demonstrates how constant-containers can be used to model complex relationships in a type-safe and immutable way, extending the capabilities of traditional enums in Java.
Check DemoTest test class for more examples.
- Exception Handling: Some operations, like attempting to retrieve an instance of an enum class via Constants.getInstance(), will throw an IllegalStateException (you should use getEnumByValue instead).
- No Support for Anonymous Classes in getInstance: The utility method getInstance does not support anonymous classes.
- Runtime Exceptions for Duplicate Keys: Containers with duplicated keys may lead to runtime exceptions, requiring careful structuring of constants to avoid such issues.
- Static Requirement for Constants: There's a requirement for constants to be static when used within certain container implementations (edge cases where not enum is used).