Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

enumus

CircleCIBuild StatuscodecovCodacy Badge

A set of utilities that make java enums more powerful.

Features

Customized valueOf()

Enum have a very convinient built-in feature - static function valueOf() that retrieves enum constant by its name. In some cases however we need something similar but based on other field. The implementation is simple: create static map, iterate over values of enum and populate the map.

publicenumColor {
RED("red"), GREEN("green"), BLUE("blue"),;
privatefinalStringtitle;
ManualColor(Stringtitle) {
this.title = title;
}
}

Thanks to Java 8 we can now right this using one line only:

privatestaticfinalMap<String, Color> titles = Arrays.stream(Color.values()).collect(Collectors.toMap(Color::getTitle, e -> e));

I found myself writing similar code many times and decidded to implemnent utility that simplifies this. Now the code can look like the following:

privatestaticfinalValueOf<Color, String> titles = newValueOf<>(Color.class, e -> e.title);

The static accessor is simple too. It should not care about throwing exception if value is not found.

publicstaticColorvalueOfTitle(Stringtitle) {
returntitles.valueOf(title);
}

The utity accepts reference to function that can implement more complicated logic than just accessing a simple field.

Range based valueOf()

The utility supports ranges as well. Visible colors are just electro magnetic waves of certain length.

ColorWave length, nm
Red700–635
Orange635–590
Yellow590–560
Green560–520

We want to define enum Rgb and get enum constant by wave length from the range. It is very easy with enumus:

publicenumRgb {
RED(635, 700), GREEN(520, 560), BLUE(450, 490),;
privatestaticfinalValueOfRange<Rgb, Integer> waveLength = newValueOfRange<>(Rgb.class, e -> e.min, e -> e.max);
privatefinalintmin;
privatefinalintmax;
Rgb(intmin, intmax) {
this.min = min;
this.max = max;
}
publicstaticRgbvalueByWaveLength(intwave) {
returnwaveLength.valueOf(wave);
} 

Enum map validator

It is very useful practice to use enum constants as the map keys. Values may contain either simple data, complex objects or often functions. Very often we want to have entry per each enum element. Unfortunately compiler will not help us to detect if new element was added to enum. In this case code can fail at rutime. Enumus helps to solve this problem:

EnumMapValidator.validateKeys(Color.class, map, "Colors map");

If for instance map does not contain entry BLUE the line above will throw IllegalStateException with message "Colors map is not complete: [RED, GREEN, [BLUE]] (keys in squire brackets are absent)"

Mirror enum

Enums can hold data and implement methods. However not all methods can be implemented in one class. Methods may delegate functionality to other classes that require external dependencies. Often we do not want to put all dependencies into one module but rather separate them among several modules. Sometimes this cause us to hold 2 or more enums with the same constants and different implementation. This can be used instead of classic Visitor pattern but even has advantage: some implementations may be optional and we can check whether the implementation is done or not without calling the actual function.

Enumus introduces term "morror" enum, that is enum that has the same entries as its mirror. The feature may be comapred with 2 classes that implement the same interface. In this case compiler checks that all methods are implemented. Mirror enum cannot enjoy the compiler's service but it is enough add one line of code in static initialiazer and exception will be thrown if enum does not reflect its mirror.

enumMissingColor {
RED, GREEN,;
static {
Mirror.mirrors(MissingColor.class, Color.class); // throws exception because BLUE is absent
}
}

Hierarchical enum

Neither enums nor their elements cannot be inherited from other class. It is becase each enum is inherited implicitly from java.lang.Enum. Some tasks however can be easier modelled using hierarchy. Enumus helps to implement hieratchical structure with enums.

publicenumOsType {
OS(null),
Windows(OS),
WindowsNT(Windows),
WindowsNTWorkstation(WindowsNT),
WindowsNTServer(WindowsNT),
Windows2000(Windows),
Windows2000Server(Windows2000),
Windows2000Workstation(Windows2000),
WindowsXp(Windows),
WindowsVista(Windows),
Windows7(Windows),
Windows95(Windows),
Windows98(Windows),
Unix(OS) {
@OverridepublicbooleansupportsXWindowSystem() {
returntrue;
}
},
Linux(Unix),
IOS(Linux),
Android(Linux),
AIX(Unix),
HpUx(Unix),
SunOs(Unix),;
privateOsTypeparent;
OsType(OsTypeparent) {
this.parent = parent;
}
}

The structure above is defined using standard Java syntax; there is no need to use external tools. However the following features may be needed here:

  • we cannot easily get list of all children of Linux
  • How to check that WindowsVista is Windows?
  • How to "inherit" method supportsXWindowSystem() in all Unix like systems?

All these can be easily done with class Hierarchy implemented by enumus. Just add the following line:

privatestaticHierarchy<OsType> hierarchy = newHierarchy<>(OsType.class, e -> e.parent);

and implementation of described above methods becomes trivial:

publicOsType[] children() {
returnhierarchy.getChildren(this);
}
publicbooleansupportsXWindowSystem() {
returnhierarchy.invoke(this, args -> false);
}
publicbooleanisA(OsTypeother) {
returnhierarchy.relate(other, this);
}

Initialization using annotations

Almost each appllication contains series of constant values like these:

publicstaticfinalStringTHREAD_COUNT_PROPERTY = "THREAD_COUNT_PROPERTY";
publicstaticfinalintTHREAD_COUNT_DEFAULT = 10;
publicstaticfinalStringCONNECTION_TIMEOUT_PROPERTY = "CONNECTION_TIMEOUT_PROPERTY";
publicstaticfinalintCONNECTION_TIMEOUT_DEFAULT = 10_000;

It is convenient to organize such constants using enums. For example instead of having a lot of groups of static final members we can put them into enum like following:

enumConfiguration {
THREAD_COUNT(10), NETWORK_TIMEOUT(10_000),;
privatefinalintvalue;
Configuration(intvalue) {this.value = value}
publicintvalue() {returnvalue;}
publicStringproperty() {returnname() + "_PROPERTY";}
}

Such enums tend to grow quickly. Sometimes they contain values that match wourse than those in example above. For exampele connection may hold read/write timeouts while threading model may become more flexible and contain minimum, maximum and default thread count. In this case we have either break the enum into separate parts or add all fields needed for all different elements together:

enumConfiguration {
THREAD_COUNT(5, 20, 10, 0, 0), // read/write timeout is irrelevant here, so we pass 0 instead NETWORK_TIMEOUT(0, 0, 10_000, 5_000, 8_000),; // min/max values are irrelevant for timeoutprivatefinalintmin;
privatefinalintmax;
privatefinalintvalue;
privatefinalintread;
privatefinalintwrite;
Configuration(intmin, intmax, intvalue, intread, intwrite) {/* initialization code*/}
}

The definitions of the enum elements became ugly. We have to pass irrelevant values just to satisfy compiler. We can define several overloaded constructors that better suite our cases. But it is not always possible. For example in this example we would liek to have 2 additional constructors:

Configuration(intmin, intmax, intvalue) {/* initialization code*/}
Configuration(intvalue, intread, intwrite) {/* initialization code*/}

But we cannot do this because both constructors have the same signature: 3 int parameters. In real life number of parameter variations may be much higher. Enumus suggests solution for this.

Enums are inititated when they are accessed first time, typically on JVM startup. So, performance is not an issue here. This means that the configuration could be done using annotations without impact on application performance. Enumus provides an extendable type safe annotation based framework for configuration of enum elements:

Integer value configured using annotation

@IntValue(name = "number", value = 2)
TWO(),

String value configured using annotation

@Value(name = "str", value = "two")
TWO(),;

Here is full example that can illustrate the usage:

publicenumOneDoubleParamTestEnumimplementsInitializable {
ZERO(), // using default constructor; the double value will be initialized to 0.0PI(3.1415926), // using regular constructor@DoubleValue(name = "number", value = 2.718281828)
E(); // the value is initialiezed using annotationprivatefinaldoublenumber;
OneDoubleParamTestEnum() {
number = $(); // default constructor that calls $() function implemented in interface Initializable
}
OneDoubleParamTestEnum(doublenumber) {
this.number = number; // regular constructor
}
}

Almost any type of argument can be supported. The following types are supported out of the box:

  • String
  • int
  • double
  • java.util.Date
  • java.util.regex.Pattern
  • any enum type

About

Library that makes java enums even more powerful

Resources

Stars

35 stars

Watchers

2 watching

Forks

Releases

Packages

Contributors

Languages