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?

5
  • You must use a compile time constant. That means no methods. You can use JobType[]. Commented Jul 6, 2015 at 11:39
  • But if declare JobType[] values() then I won't be able to reuse the @Exclude for other types of Enum. Commented Jul 6, 2015 at 11:41
  • Possible duplicate: stackoverflow.com/questions/3271659/… Commented Jul 6, 2015 at 11:42
  • 1
    You can use public static final constants. Commented Jul 6, 2015 at 11:42
  • I tried to trick Java with 'public static final String S = JobType.S.name();' but it's more clever than that. :-( Commented Jul 6, 2015 at 11:58

1 Answer 1

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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!
@AdamHorvath the Javadoc specifically states that they think it is unlikely that people will be renaming enum constants... See Enum.name(). That said, if you're worried about it, you could use toString() instead of name(), though of course that has its own risks.
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.
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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.