9

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?

Bendy
  • 3,506
  • 6
  • 40
  • 71
Adam Horvath
  • 1,249
  • 1
  • 10
  • 25

1 Answers1

1

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:

  1. Make it easy for you to do different filtration behavior for each different filter type.
  2. 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.

Community
  • 1
  • 1
durron597
  • 31,968
  • 17
  • 99
  • 158
  • For me, the important thing was if someone is refactoring the Enum's members (or their name) with an IDE, then the final Strings wouldn't contain the right name()-s. But with your solution it won't happen. Thank you for the answer! – Adam Horvath Jul 07 '15 at 07:43
  • @AdamHorvath the Javadoc specifically states that they think it is unlikely that people will be renaming enum constants... See [`Enum.name()`](http://docs.oracle.com/javase/7/docs/api/java/lang/Enum.html#name()). That said, if you're worried about it, you could use `toString()` instead of `name()`, though of course that has its own risks. – durron597 Jul 07 '15 at 12:01
  • True, with a reasonable application. But in our "crazy" company we use Enums extensively. The toString() changes even more often, as we attach human-readable names to it; like JobType.S.toString() is "Sample". If you specify EnumType.STRING on your columns than it remains somewhat manageable. – Adam Horvath Jul 07 '15 at 12:34
  • You could require that all the enums implement an `interface ImmutableName { String immutableName(); }` which is guaranteed not to change on IDE refactoring... but there would be no way to enforce people implementing the interface, nor actually guaranteeing that `immutableName` doesn't change. I'm making an edit to my answer now. – durron597 Jul 07 '15 at 13:15