Java Annotation - array of Objects or toString values - java

I need to write an Annotation to exclude certain values from a result set.
Background:
Distinct values are selected from fields and are listed in a ComboBox. Some of the legacy values are Deprecated and I don't want to show them, even if they are returned by JDBC's SELECT DISTINCT(). It's like a mini-framework where people can build select queries by clicking values from ComboBoxes.
I tried the following (the code does not compile - commented lines are the ways I tried to solve the problem):
public enum JobType {
//...
S,
//...
}
public #interface Exclude {
Object[] values(); // Invalid type
Enum[] values(); // Invalid type again
String[] values(); // Accepts but see the following lines
}
#Table(name = "jobs_view")
public class JobSelectionView extends View {
//...
#Exclude(values = {JobType.S.toString()}) // Not a constant expression
#Exclude(values = {JobType.S.name()}) // Not a constant expression ?!?!?!
#Exclude(values = {"S"}) // Works but... come on!
#Enumerated(value = EnumType.STRING)
#Column(name = "type")
private JobType type;
//...
}
I don't like using {"S"}, any suggestions?

But if declare JobType[] values() then I won't be able to reuse the #Exclude for other types of Enum.
This is the best way to do what you want, though. Here's the thing:
The class Enum is, itself, meaningless.
It only gains meaning when subclassed. Let's say you want to add another filter, say Color (your own custom Color enum, not java.awt.Color). Obviously, the thing thing that your filtration class is doing is very different for filtering out JobType than it would be for filtering out Color!
Therefore, the best thing to do would be to have each different time of enum you're trying to filter in it's own argument, e.g.
public #interface Exclude {
JobType[] jobs;
Color[] colors;
Foo[] foos;
Quux[] quuxes;
}
This will accomplish two things:
Make it easy for you to do different filtration behavior for each different filter type.
Make the #Excludes annotation more legibile by sorting the different parameters into different groups.
The Javadoc for Enum.name() says:
Returns the name of this enum constant, exactly as declared in its enum declaration. Most programmers should use the toString() method in preference to this one, as the toString method may return a more user-friendly name. This method is designed primarily for use in specialized situations where correctness depends on getting the exact name, which will not vary from release to release.
I suggest you try to tell the people in your company to read up on the Open/Closed principle and explain why violating it would be particularly damaging in this case.

Related

What is #AutoAnnotation for? How could it be used?

In https://dagger.dev/multibindings.html, I read about #AutoAnnotation. It has a reference to https://github.com/google/auto/blob/master/value/src/main/java/com/google/auto/value/AutoAnnotation.java.
It is also mentioned in
https://github.com/google/auto/blob/57dfad360306619a820e6aae4a14a1aa67c29299/value/userguide/howto.md#annotation
I read about it, can't get to understand it.
I manage to access it from my Android code using
implementation 'com.google.auto.value:auto-value:1.5.2'
kapt 'com.google.auto.value:auto-value:1.5.2'
And also
android.defaultConfig.javaCompileOptions.annotationProcessorOptions.includeCompileClasspath = true
But I don't understand how it could be used. Is there any good tutorial of using it?
AutoAnnotation automatically generates a class that implements an annotation interface in the same way the JDK does.
Dagger map keys
When using a Multibindings map through Dagger that uses a custom annotation as its key, Dagger will install the instance T or Provider Provider<T> into the returned map, using the annotation instance itself as the key. To make this clearer:
#MapKey
#interface YourAnnotation {
String foo();
}
#Provides #YourAnnotation(foo="bar") YourClass getYourClassForBar() { /* ... */ }
// Dagger will create a multibinding that would allow you to inject this:
#Inject Map<YourAnnotation, YourClass> map;
If the only thing that matters here is foo, you could also use unwrapKeys to make the map keyed by String instead of YourAnnotation, but let's assume you want this because you want YourAnnotation to have multiple values in the future. But where do the implementations of YourAnnotation come from, and how are you supposed to call get on the map?
Annotations at runtime
When you annotate a Java element (frequently a class, method, or field) Java will return a particular implementation of that class's annotation. From the Java tutorial:
#interface ClassPreamble {
String author();
String date();
int currentRevision() default 1;
String lastModified() default "N/A";
String lastModifiedBy() default "N/A";
// Note use of array
String[] reviewers();
}
// [...]
#ClassPreamble (
author = "John Doe",
date = "3/17/2002",
currentRevision = 6,
lastModified = "4/12/2004",
lastModifiedBy = "Jane Doe",
// Note array notation
reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List {/* ... */}
In this usage, Generation3List has one Annotation of type ClassPreamble. If the annotation is retained at runtime (i.e. ClassPreamble itself is annotated with #Retention(RUNTIME)), you can get to it via Generation3List.class.getAnnotations() or Generation3List.class.getAnnotation(ClassPreamble.class). (There are also declared counterparts that handle superclass annotations differently.)
Once you get to an instance of ClassPreamble, you can use the methods like author() and date() to retrieve the data out of the class. However, ClassPreamble behaves as an interface, and the implementation of that annotation is internal to the VM. That makes it more difficult to create your own arbitrary instance of ClassPreamble at runtime.
Conforming annotation implementations
Because YourAnnotation and ClassPreamble are interfaces, you could just create an implementation. However, that implementation is unlikely to have matching implementations of equals and hashCode compared to the VM's implementation, because the implementation may vary between JREs and may also vary in Android. However, the implementation of equals and hashCode is actually very closely prescribed in the docs for Annotation:
The hash code of an annotation is the sum of the hash codes of its members (including those with default values), as defined below: The hash code of an annotation member is (127 times the hash code of the member-name as computed by String.hashCode()) XOR the hash code of the member-value, as defined below [...]
Returns true if the specified object represents an annotation that is logically equivalent to this one. In other words, returns true if the specified object is an instance of the same annotation type as this instance, all of whose members are equal to the corresponding member of this annotation, as defined below [...]
It is possible to manually implement these rules, but it would be difficult to do so, and it would also impose a burden if the structure of YourAnnotation or ClassPreamble were to change. Though there are reflective solutions to this problem, AutoAnnotation generates the code for a conforming implementation automatically:
public class YourAnnotations {
#AutoAnnotation public static YourAnnotation yourAnnotation(String foo) {
return new AutoAnnotation_YourAnnotations_yourAnnotation(foo);
}
}
public class ClassPreambles {
#AutoAnnotation public static ClassPreamble classPreamble(
String author,
String date,
int currentRevision,
String lastModified,
String lastModifiedBy,
String[] reviewers) {
return new AutoAnnotation_ClassPreambles_classPreamble(
author,
date,
currentRevision,
lastModified,
lastModifiedBy,
reviewers);
}
}
With AutoAnnotation's generated implementation, you can call get on the map that Dagger Multibindings generates (or provide test implementations you control) without having to deal with Annotation-specific hashCode XORs or equals rules. This is useful beyond Dagger and tests, but because Dagger uses annotation instances in its maps, it makes sense that you might need to use AutoAnnotation to create similar instances.

Why is it bad practice to allow to set a collection?

Let's say we have a class with a simple collection (a list for instance). The class contains a constructor, getters and setters.
I've been told that it is a bad practice to set the collection directly.
class Example{
private String id;
private List<String> names;
public Example(String id, List<String> names){
this.id = id;
this.names = names;
}
public String getId(){
return id;
}
public List<String> getNames(){
return names;
}
public void setId(String id){
this.id = id;
}
public void setNames(List<String> names){
this.names = names;
}
}
Can anyone point the disadvantages of writing the method setNames()?
The logic behind set and get operations is to allow validation or replacing of inner representation, if you let an external class set the specific implementation, you lose control over the insertion logic (allows duplicates? is ordered?, is mutable?), and you make you object harder to use, as the users of it have to decide that, when is very probable that they don't care.
Since the private variable names is owned by your class you can ensure that you have control over its contents within the class. If you change the reference of that variable to a list that gets passed in then you no longer are certain that your instance won't be changed externally since both your class AND the class that passed the new list instance will both have a reference/access to it. Same is true with getNames() - any class that calls that method now has full access to change the contents of the list externally from the class.
That would give you two ways of changing the contents (getNames().add(...) vs. setNames(Arrays.asList(...))).
This is confusing.
You should pick a single option and make the other option impossible.
A lot of the builtin collections are mutable, so storing such a value may allow an external class to modify the internal state of your Example is a way you did not plan. Consider the following snippet:
List<Stirng> names = new ArrayList<>();
names.add("Stack");
names.add("Overflow");
Example example = new Example();
example.setNames(names);
// example.getNames() returns ["Stack", "Overflow"]
names.add("Exchange");
// example.getNames now returns ["Stack", "Overflow", "Exchange"]!
A safer approach could be to copy the contents of the passed list:
public void setNames(List<String> names){
this.names = new ArrayList<>(names);
}
A slightly different answer to those here already is that setters are a bad practice (*), whether you're setting a collection property or some other type.
To quote Effective Java 2nd Ed Item 15: "Minimize mutability":
There are many good reasons for [making classes immutable]: Immutable classes
are easier to design, implement, and use than mutable classes. They are less prone
to error and are more secure.
There is also a description of immutable classes in the Oracle tutorial.
(*) That's not to say that you should never use them; just that you should design classes to be immutable as a default position, and only make them mutable in the few occasions where it is actually required - and that's less often than you might imagine. To quote the same item in Effective Java:
Classes should be immutable unless there’s a very good reason to make them
mutable
Using get and set methods allows you to perform verification and validation on the input before it can cause problems. It can also be used to transform info going into and out of your system for the convenience of the program and user.
Edit
Just to be clear defensive measures are part of the verification and validation I was talking about.

Reason to use enums? [duplicate]

I am very familiar with C# but starting to work more in Java. I expected to learn that enums in Java were basically equivalent to those in C# but apparently this is not the case. Initially I was excited to learn that Java enums could contain multiple pieces of data which seems very advantageous (http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html). However, since then I have found a lot of features missing that are trivial in C#, such as the ability to easily assign an enum element a certain value, and consequently the ability to convert an integer to an enum without a decent amount of effort (i.e. Convert integer value to matching Java Enum).
So my question is this: is there any benefit to Java enums over a class with a bunch of public static final fields? Or does it just provide more compact syntax?
EDIT: Let me be more clear. What is the benefit of Java enums over a class with a bunch of public static final fields of the same type? For example, in the planets example at the first link, what is the advantage of an enum over a class with these public constants:
public static final Planet MERCURY = new Planet(3.303e+23, 2.4397e6);
public static final Planet VENUS = new Planet(4.869e+24, 6.0518e6);
public static final Planet EARTH = new Planet(5.976e+24, 6.37814e6);
public static final Planet MARS = new Planet(6.421e+23, 3.3972e6);
public static final Planet JUPITER = new Planet(1.9e+27, 7.1492e7);
public static final Planet SATURN = new Planet(5.688e+26, 6.0268e7);
public static final Planet URANUS = new Planet(8.686e+25, 2.5559e7);
public static final Planet NEPTUNE = new Planet(1.024e+26, 2.4746e7);
As far as I can tell, casablanca's answer is the only one that satisfies this.
Type safety and value safety.
Guaranteed singleton.
Ability to define and override methods.
Ability to use values in switch statement case statements without qualification.
Built-in sequentialization of values via ordinal().
Serialization by name not by value, which offers a degree of future-proofing.
EnumSet and EnumMap classes.
Technically one could indeed view enums as a class with a bunch of typed constants, and this is in fact how enum constants are implemented internally. Using an enum however gives you useful methods (Enum javadoc) that you would otherwise have to implement yourself, such as Enum.valueOf.
Nobody mentioned the ability to use them in switch statements; I'll throw that in as well.
This allows arbitrarily complex enums to be used in a clean way without using instanceof, potentially confusing if sequences, or non-string/int switching values. The canonical example is a state machine.
The primary advantage is type safety. With a set of constants, any value of the same intrinsic type could be used, introducing errors. With an enum only the applicable values can be used.
For example
public static final int SIZE_SMALL = 1;
public static final int SIZE_MEDIUM = 2;
public static final int SIZE_LARGE = 3;
public void setSize(int newSize) { ... }
obj.setSize(15); // Compiles but likely to fail later
vs
public enum Size { SMALL, MEDIUM, LARGE };
public void setSize(Size s) { ... }
obj.setSize( ? ); // Can't even express the above example with an enum
There is less confusion. Take Font for instance. It has a constructor that takes the name of the Font you want, its size and its style (new Font(String, int, int)). To this day I cannot remember if style or size goes first. If Font had used an enum for all of its different styles (PLAIN, BOLD, ITALIC, BOLD_ITALIC), its constructor would look like Font(String, Style, int), preventing any confusion. Unfortunately, enums weren't around when the Font class was created, and since Java has to maintain reverse compatibility, we will always be plagued by this ambiguity.
Of course, this is just an argument for using an enum instead of public static final constants. Enums are also perfect for singletons and implementing default behavior while allowing for later customization (I.E. the strategy pattern). An example of the latter is java.nio.file's OpenOption and StandardOpenOption: if a developer wanted to create his own non-standard OpenOption, he could.
There are many good answers here, but none mentiones that there are highly optimized implementations of the Collection API classes/interfaces specifically for enums:
EnumSet
EnumMap
These enum specific classes only accept Enum instances (the EnumMap only accept Enums only as keys), and whenever possible, they revert to compact representation and bit manipulation in their implementation.
What does this mean?
If our Enum type has no more that 64 elements (most of real-life Enum examples will qualify for this), the implementations store the elements in a single long value, each Enum instance in question will be associated with a bit of this 64-bit long long. Adding an element to an EnumSet is simply just setting the proper bit to 1, removing it is just setting that bit to 0. Testing if an element is in the Set is just one bitmask test! Now you gotta love Enums for this!
example:
public class CurrencyDenom {
public static final int PENNY = 1;
public static final int NICKLE = 5;
public static final int DIME = 10;
public static final int QUARTER = 25;}
Limitation of java Constants
1) No Type-Safety: First of all it’s not type-safe; you can assign any valid int value to int e.g. 99 though there is no coin to represent that value.
2) No Meaningful Printing: printing value of any of these constant will print its numeric value instead of meaningful name of coin e.g. when you print NICKLE it will print "5" instead of "NICKLE"
3) No namespace: to access the currencyDenom constant we need to prefix class name e.g. CurrencyDenom.PENNY instead of just using PENNY though this can also be achieved by using static import in JDK 1.5
Advantage of enum
1) Enums in Java are type-safe and has there own name-space. It means your enum will have a type for example "Currency" in below example and you can not assign any value other than specified in Enum Constants.
public enum Currency {PENNY, NICKLE, DIME, QUARTER};
Currency coin = Currency.PENNY;
coin = 1; //compilation error
2) Enum in Java are reference type like class or interface and you can define constructor, methods and variables inside java Enum which makes it more powerful than Enum in C and C++ as shown in next example of Java Enum type.
3) You can specify values of enum constants at the creation time as shown in below example:
public enum Currency {PENNY(1), NICKLE(5), DIME(10), QUARTER(25)};
But for this to work you need to define a member variable and a constructor because PENNY (1) is actually calling a constructor which accepts int value , see below example.
public enum Currency {
PENNY(1), NICKLE(5), DIME(10), QUARTER(25);
private int value;
private Currency(int value) {
this.value = value;
}
};
Reference: https://javarevisited.blogspot.com/2011/08/enum-in-java-example-tutorial.html
The first benefit of enums, as you have already noticed, is syntax simplicity. But the main point of enums is to provide a well-known set of constants which, by default, form a range and help to perform more comprehensive code analysis through type & value safety checks.
Those attributes of enums help both a programmer and a compiler. For example, let's say you see a function that accepts an integer. What that integer could mean? What kind of values can you pass in? You don't really know right away. But if you see a function that accepts enum, you know very well all possible values you can pass in.
For the compiler, enums help to determine a range of values and unless you assign special values to enum members, they are well ranges from 0 and up. This helps to automatically track down errors in the code through type safety checks and more. For example, compiler may warn you that you don't handle all possible enum values in your switch statement (i.e. when you don't have default case and handle only one out of N enum values). It also warns you when you convert an arbitrary integer into enum because enum's range of values is less than integer's and that in turn may trigger errors in the function that doesn't really accept an integer. Also, generating a jump table for the switch becomes easier when values are from 0 and up.
This is not only true for Java, but for other languages with a strict type-checking as well. C, C++, D, C# are good examples.
An enum is implictly final, with a private constructors, all its values are of the same type or a sub-type, you can obtain all its values using values(), gets its name() or ordinal() value or you can look up an enum by number or name.
You can also define subclasses (even though notionally final, something you can't do any other way)
enum Runner implements Runnable {
HI {
public void run() {
System.out.println("Hello");
}
}, BYE {
public void run() {
System.out.println("Sayonara");
}
public String toString() {
return "good-bye";
}
}
}
class MYRunner extends Runner // won't compile.
enum Benefits:
Enums are type-safe, static fields are not
There is a finite number of values (it is not possible to pass non-existing enum value. If you have static class fields, you can make that mistake)
Each enum can have multiple properties (fields/getters) assigned - encapsulation. Also some simple methods: YEAR.toSeconds() or similar. Compare: Colors.RED.getHex() with Colors.toHex(Colors.RED)
"such as the ability to easily assign an enum element a certain value"
enum EnumX{
VAL_1(1),
VAL_200(200);
public final int certainValue;
private X(int certainValue){this.certainValue = certainValue;}
}
"and consequently the ability to convert an integer to an enum without a decent amount of effort"
Add a method converting int to enum which does that. Just add static HashMap<Integer, EnumX> containing the mapping.
If you really want to convert ord=VAL_200.ordinal() back to val_200 just use: EnumX.values()[ord]
You get compile time checking of valid values when you use an enum. Look at this question.
The biggest advantage is enum Singletons are easy to write and thread-safe :
public enum EasySingleton{
INSTANCE;
}
and
/**
* Singleton pattern example with Double checked Locking
*/
public class DoubleCheckedLockingSingleton{
private volatile DoubleCheckedLockingSingleton INSTANCE;
private DoubleCheckedLockingSingleton(){}
public DoubleCheckedLockingSingleton getInstance(){
if(INSTANCE == null){
synchronized(DoubleCheckedLockingSingleton.class){
//double checking Singleton instance
if(INSTANCE == null){
INSTANCE = new DoubleCheckedLockingSingleton();
}
}
}
return INSTANCE;
}
}
both are similar and it handled Serialization by themselves by implementing
//readResolve to prevent another instance of Singleton
private Object readResolve(){
return INSTANCE;
}
more
Another important difference is that java compiler treats static final fields of primitive types and String as literals. It means these constants become inline. It's similar to C/C++ #define preprocessor. See this SO question. This is not the case with enums.
Enums can be local
As of Java 16, an enum can be defined locally (within a method). This scope is in addition to being able to define an enum as nested or as separate class.
This new local definition scope came along with the new records feature. See JEP 395: Records for details. Enums, interfaces, and records can all be defined locally in Java 16+.
In contrast, public static final fields always have global scope.
I think an enum can't be final, because under the hood compiler generates subclasses for each enum entry.
More information From source
There are many advantages of enums that are posted here, and I am creating such enums right now as asked in the question.
But I have an enum with 5-6 fields.
enum Planet{
EARTH(1000000, 312312321,31232131, "some text", "", 12),
....
other planets
....
In these kinds of cases, when you have multiple fields in enums, it is much difficult to understand which value belongs to which field as you need to see constructor and eye-ball.
Class with static final constants and using Builder pattern to create such objects makes it more readable. But, you would lose all other advantages of using an enum, if you need them.
One disadvantage of such classes is, you need to add the Planet objects manually to the list/set of Planets.
I still prefer enum over such class, as values() comes in handy and you never know if you need them to use in switch or EnumSet or EnumMap in future :)
Main reason: Enums help you to write well-structured code where the semantic meaning of parameters is clear and strongly-typed at compile time - for all the reasons other answers have given.
Quid pro quo: in Java out of the box, an Enum's array of members is final. That's normally good as it helps value safety and testing, but in some situations it could be a drawback, for example if you are extending existing base code perhaps from a library. In contrast, if the same data is in a class with static fields you can easily add new instances of that class at runtime (you might also need to write code to add these to any Iterable you have for that class). But this behaviour of Enums can be changed: using reflection you can add new members at runtime or replace existing members, though this should probably only be done in specialised situations where there is no alternative: i.e. it's a hacky solution and may produce unexpected issues, see my answer on Can I add and remove elements of enumeration at runtime in Java.
You can do :
public enum Size { SMALL(1), MEDIUM(2), LARGE(3) };
private int sizeValue;
Size(sizeValue) {this.sizeValue = value; }
So with this you can get size value like this SMALL.getSizeValue();
If you want to set sizes Enums are not for you, if you will be only define constants and fixed values are fine.
Check this link maybe can help you

Compiletime validation of enum parameters

There is a constructor with three parameters of type enum:
public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3)
{...}
The three parameters of type enum are not allowd to be combined with all possible values:
Example:
EnumType1.VALUE_ONE, EnumType2.VALUE_SIX, EnumType3.VALUE_TWENTY is a valid combination.
But the following combination is not valid:
EnumType1.VALUE_TWO, EnumType2.VALUE_SIX, EnumType3.VALUE_FIFTEEN
Each of the EnumTypes knows with which values it is allowed to be combined:
EnumType1 and the two others implement a isAllowedWith() method to check that as follows:
public enum EnumType1 {
VALUE_ONE,VALUE_TWO,...;
public boolean isAllowedWith(final EnumType2 type) {
switch (this) {
case VALUE_ONE:
return type.equals(Type.VALUE_THREE);
case VALUE_TWO:
return true;
case VALUE_THREE:
return type.equals(Type.VALUE_EIGHT);
...
}
}
I need to run that check at compile time because it is of extreme importance in my project that the combinations are ALWAYS correct at runtime.
I wonder if there is a possibility to run that check with user defined annotations?
Every idea is appreciated :)
The posts above don't bring a solution for compile-time check, here's mine:
Why not use concept of nested Enum.
You would have EnumType1 containing its own values + a nested EnumType2 and this one a nested EnumType3.
You could organize the whole with your useful combination.
You could end up with 3 classes (EnumType1,2 and 3) and each one of each concerned value containing the others with the allowed associated values.
And your call would look like that (with assuming you want EnumType1.VALUE_ONE associated with EnumType2.VALUE_FIFTEEN) :
EnumType1.VALUE_ONE.VALUE_FIFTEEN //second value corresponding to EnumType2
Thus, you could have also: EnumType3.VALUE_SIX.VALUE_ONE (where SIX is known by type3 and ONE by type1).
Your call would be change to something like:
public SomeClass(EnumType1 enumType)
=> sample:
SomeClass(EnumType1.VALUE_ONE.VALUE_SIX.VALUE_TWENTY) //being a valid combination as said
To better clarify it, check at this post: Using nested enum types in Java
So the simplest way to do this is to 1) Define the documentation to explain valid combinations and
2) add the checks in the constructor
If a constructor throws an Exception than that is the responsibility of the invoker. Basically you would do something like this:
public MyClass(enum foo, enum bar, enum baz)
{
if(!validateCombination(foo,bar,baz))
{
throw new IllegalStateException("Contract violated");
}
}
private boolean validateCombination(enum foo, enum bar, enum baz)
{
//validation logic
}
Now this part is absolutely critical. Mark the class a final, it is possible that a partially constructed object can be recovered and abused to break your application. With a class marked as final a malicious program cannot extend the partially constructed object and wreak havoc.
One alternative idea is to write some automated tests to catch this, and hook them into your build process as a compulsory step before packaging/deploying your app.
If you think about what you're trying to catch here, it's code which is legal but wrong. While you could catch that during the compilation phase, this is exactly what tests are meant for.
This would fit your requirement of not being able to build any code with an illegal combination, because the build would still fail. And arguably it would be easier for other developers to understand than writing your own annotation processor...
The only way I know is to work with annotations.
Here is what I do I mean.
Now your constructor accepts 3 parameters:
public SomeClass(EnumType1 enum1,EnumType2 enum2, EnumType3 enum3){}
so you are calling it as following:
SomeClass obj = new SomeClass(EnumTupe1.VALUE1, EnumTupe2.VALUE2, EnumTupe1.VALUE3)
Change the constructor to be private. Create public constructor that accept 1 parameter of any type you want. It may be just a fake parameter.
public SomeClass(Placeholder p)
Now you have to require to call this constructor while each argument is annotated with special annotation. Let's call it TypeAnnotation:
SomeClass obj = new SomeClass(TypeAnnotation(
type1=EnumType1.VALUE1,
type2=EnumTupe2.VALUE2,
type3=EnumTupe1.VALUE3)
p3);
The call is more verbose but this is what we have to pay for compile time validation.
Now, how to define the annotation?
#Documented
#Retention({RetentionPolicy.RUNTIME, RetentionPolicy.SOURCE})
#Target(PARAMETER)
#interface TypeAnnotation {
EnumType1 type1();
EnumType2 type3();
EnumType3 type3();
}
Please pay attention that target is PARAMETER and retention values are RUNTIME and SOURCE.
RUNTIME allows reading this annotation at runtime, while SOURCE allows creating annotation processor that can validate the parameters at runtime.
Now the public constructor will call the 3-parameters private construcor:
public SomeClass(Placeholder p) {
this(readAnnotation(EnumType1.class), readAnnotation(EnumType2.class), readAnnotation(EnumType3.class), )
}
I am not implementing readAnnotation() here: it should be static method that takes stack trace, goes 3 elements back (to caller of the public costructor) and parses annotation TypeAnnotation.
Now is the most interesting part. You have to implement annotation processor.
Take a look here for instructions and here for an example of annotation processor.
You will have to add usage of this annotation processor to your build script and (optionally) to your IDE. In this case you will get real compilation error when your compatibility rules are violated.
I believe that this solution looks too complicated but if you really need this you can do this. It may take a day or so. Good luck.
Well, I am not aware of a compile time check but I do not think it is possible because how can the compiler know which value will be passed to the constructor (In case the value of your enum variable is calculated in runtime (e.g. by an If clause) ?
This can only be validated on runtime by using a validator method as you implemented for the enum types.
Example :
If in your code you have something like this :
EnumType1 enumVal;
if (<some condition>) {
enumVal = EnumType2.VALUE_SIX;
} else {
enumVal = EnumType2.VALUE_ONE;
}
There is no way the compiler can know which of the values will be assigned to enumVal so it won't be able to verify what is passed to the constructor until the if block is evaluated (which can be done only in runtime)

How to remove the dependency on a Java enum's values?

[Mind the gap: I know that the best solution would be to get rid of the enum completely, but that's not an option for today as mentioned in the comments, but it is planned for the (far) future.]
We have two deployment units: frontend and backend. The frontend uses an enum and calls an EJB service at the backend with the enum as a parameter. But the enum changes frequently, so we don't want the backend to know its values.
String constants
A possible solution would be to use String constants insteadof enums, but that would cause a lot of little changes at the frontend. I'm searching a solution, which causes as few changes as possible in the frontend.
Wrapper class
Another solution is the usage of a wrapper class with the same interface as an enum. The enum becomes an wrapper class and the enum values become constants within that wrapper. I had to write some deserialization code to ensure object identity (as enums do), but I don't know if it is a correct solution. What if different classloaders are used?
The wrapper class will implement a Java interface, which will replace the enum in the backend. But will the deserialiaztion code execute in the backend even so?
Example for a wrapper class:
public class Locomotion implements Serializable {
private static final long serialVersionUID = -6359307469030924650L;
public static final List<Locomotion> list = new ArrayList<Locomotion>();
public static final Locomotion CAR = createValue(4654L);
public static final Locomotion CYCLE = createValue(34235656L);
public static final Locomotion FEET = createValue(87687L);
public static final Locomotion createValue(long type) {
Locomotion enumValue = new Locomotion(type);
list.add(enumValue);
return enumValue;
}
private final long ppId;
private Locomotion(long type) {
this.ppId = type;
}
private Object readResolve() throws ObjectStreamException {
for (Locomotion enumValue : list) {
if (this.equals(enumValue)) {
return enumValue;
}
}
throw new InvalidObjectException("Unknown enum value '" + ppId + "'");
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (ppId ^ (ppId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Locomotion)) {
return false;
}
Locomotion other = (Locomotion) obj;
if (ppId != other.ppId) {
return false;
}
return true;
}
}
Did you already had the same problem? How did you solved it?
Ok, let me see if I understand. You said that
"The frontend uses an enum and calls
an EJB service at the backend with the
enum as a parameter. But the enum
changes frequently, so we don't want
the backend to know its values"
When you say "values" I assume you are referring to the numeric value you pass in the enum constructor and not to the enum constants themselves.
Therefore, this implies that the frontend and the backend will have two different versions of the enum class, but the enum constants in them will be the same.
I am only assuming the communication is via RMI (but this is not entirely clear in your post).
Now, serialization/deserialization of enums works different than with other objects. According to the Java Serialization Specification, when a enum is serialized, only its name is serialized. And when it is deserialized, it is built using the Enum.valueOf(name) method.
So, your original wrapper proposal would not work, because the server, due to stipulated serialization of Enums will never know the actual value of the enums in the client.
Bottom line, if you intend to pass an enum to the server there is no possible way to do what you pretend to do because the values in the frontend will never reach the backend if serialization is implied.
If RMI is implied, a good solution would be to use code mobility, this way you could place the problematic class in a repository accessible to both, server and client, and when the frontend developers change the class definition, you can publish the class in the repository and the server can get it from there.
See this article about dynamic code downloading using code base property in RMI
http://download.oracle.com/javase/6/docs/technotes/guides/rmi/codebase.html
Another possible solution is that you could stop using a Java Enum and use Java class with final constants, as we used to do in the old days before enums, and that way you can ensure that its values will be properly serialized when they are are sent to the backend.
Somewhat like this
public class Fruit implements Serializable{
private static final long serialVersionUID = 1L;
public final Fruit ORANGE = new Fruit("orange");
public final Fruit LEMON = new Fruit("lemon");
private String name;
private Fruit(String name){
this.name = name;
}
}
This way you can be in full control of what happens upon deserialization and your wrapper pattern might work this way.
This type of construction cannot substitute an enum completely, for instance, it cannot be used in switch statements. But, if this is an issue, you could use this object as the parameter sent to the server, and let the server rebuild the enum out of it with its version of the enum class.
Your enum, therefore, could have two new methods, one to build Java instances out of the enum itself:
public static Fruit toFruit(FruitEnum enum);
public FruitEnum valueOf(Fruit fruit);
And you can use those to convert back and forth versions of the parameter for the server.
It's an odd request, as i would think the server should know about the values of what is going into the database, but ok, i'll play along. Perhaps you could do this
public enum Giant {Fee, Fi, Fo, Fum};
public void client() {
Giant giant = Giant.Fee;
server(giant);
}
public void server(Enum e) {
String valueForDB = e.name();
//or perhaps
String valueForDB = e.toString();
}
For data transfer between frontend and backend both need to use the same class versions because of possible serialization during marshalling parameters. So again they have to know exactly the same enums or whatever other classes you try to use. Switching enums to something different won't work either. You have to set on a known class identiy for both.
So if the server should do actions based on some kind of processing/calculating the values of the parameters use strings or whatever other non-changing class you decide on and put your values inside: string of characters, array of numbers or whatever.
So if you put your database id inside the wrapper object the server will be able to get the objects out of the database. But still - they both need exact the same version of the wrapper class in their classpaths.
Okay, I can't be too exact because I don't see your code but in my experience something that changes like that should be external data, not enums.
What I almost always find is that if I externalize the information that was in the enums, then I have to externalize a few other pieces as well, but after doing it all I end up factoring away a LOT of code.
Any time you actually use the values of an enum you are almost certainly writing duplicate code. What I mean is that if you have enums like "HEARTS", "DIAMONDS"...
The ONLY way they can be used in your code is in something like a switch statement:
switch(card.suit)
case Suit.HEARTS:
load_graphic(Suit.HEARTS);
// or better yet:
Suit.HEARTS.loadGraphic();
break;
case Suit.SPADES:
Suit.SPADES.loadGraphic();
...
Now, this is obviously stupid but I made the stupid constraint to say that you USED the values in the code. My assertion is that if you don't USE the values you don't need an enum--Let's not use the values in code and see:
card.suit.loadGraphic();
Wow, all gone. But suddenly, the entire point of using an enum is gone--instead you get rid of the whole class preload a "Suit" factory with 4 instances from a text file with strings like "Heart.png" and "Spade.png".
Nearly every time I use enums I end up factoring them out like this.
I'm not saying there isn't any code that can benefit from enums--but the better that I get at factoring code and externalizing data, the less I can imagine really needing them.

Categories