0

I need to create the Enum class for authentication. Each enum need to store a Map<String,Set>.So, I know how to create a Enum, but set values into map and set seems weird. Maybe you have idea, how do it better? Code I have:

public enum Auth{
  NO_AUTH(new HashMap<>()),
  Auth(new HashMap<>());
  private Map<String,Set<String>> fields;

  private Auth(Map<String,Set<String>> fields){
    this.fields = fields;
  }
}

I want to fill my map, like that:

NO_AUTH(new HashMap<String>().put(1,new HashSet<String>().add("2"));
Yuri Molodyko
  • 590
  • 6
  • 20
  • 2
    Do you want those to be mutable? In that case: don't. `enum` values should absolutely be immutable. You *can* do it differently, but it's a really bad idea. – Joachim Sauer Aug 12 '21 at 13:31
  • I don't want mutable data. Just store and read. – Yuri Molodyko Aug 12 '21 at 13:32
  • 1
    What is the problem with your current code? Are you having trouble adding multiple values to the map? Or do you just want a cleaner way of doing it? – Charlie Armstrong Aug 12 '21 at 13:33
  • I just want a cleaner way to do it – Yuri Molodyko Aug 12 '21 at 13:33
  • 2
    This is really just "*How do I a create a map / set with a fluent interface?*" in disguise. Your code works perfectly fine passing `Map.of(1, Set.of(2))` as an argument. The problem is that `put` and `add` on HashMap and HashSet return the wrong types. They're not designed to be used in a fluent way. – Michael Aug 12 '21 at 13:33

1 Answers1

2

You just want some builder which lets you build your maps and sets in-line.

Java 9 added some:

public enum Auth{
    NO_AUTH(Map.of("1", Set.of("2"))),
    Auth(Map.of("2", Set.of("3")));
    
    private Map<String, Set<String>> fields;

    Auth(Map<String, Set<String>> fields){
        this.fields = fields;
    }
}

There are probably others in various libraries. In the worst case where you don't have access to any Map/Set builders, you can switch over the identity in the ctor:

public enum Auth {
    NO_AUTH,
    AUTH;

    private final Map<String, Set<String>> fields = new HashMap<>();

    Auth(){
        Map<String, Set<String>> tmp = new HashMap<>();
        switch (this) {
            case NO_AUTH:
                tmp.put("1", Collections.singleton("2"));
                break;
            case AUTH:
                tmp.put("2", Collections.singleton("3"));
                break;
            default:
                throw new RuntimeException("Missing case for " + this);
        }
        this.fields = Collections.unmodifiableMap(tmp);
    }
}
Michael
  • 41,989
  • 11
  • 82
  • 128
  • I'd strongly encourage use of `Collection.unmodifiableMap` to avoid mutation of the returned `Map` in the pre-9 version of the code. – Joachim Sauer Aug 12 '21 at 13:46
  • 1
    I think I'd write map/set builders rather than opting for this switch :/ – Andy Turner Aug 12 '21 at 13:46
  • @JoachimSauer In most cases I would throw that wrapper around the map inside the map's getter. Sure, it creates the wrapper more times than is strictly necessary but in 95% of cases it won't matter. All the ways I can think of to instantiate the field using unmodifiableMap are a bit too fiddly – Michael Aug 12 '21 at 13:52
  • I'd do `Map> content` before the switch. Assign to that and have `this.fields = Collections.umodifiableMap(content)` at the end of the constructor. Whether or not that's too fiddly, depends on personal taste, I guess. I just like to *guarantee* that nothing can modify my maps, even accidentally by not letting unprotected references stay around. But I guess Java 9 avoided that problem altogether. – Joachim Sauer Aug 12 '21 at 13:54
  • @JoachimSauer Yeah, actually thinking about it, it's not terrible. It's still not how I'd personally do it - I trust myself to remember to add to wrapper in the getter. But as something someone might copy-paste into their project who I can't trust to do the same, your way is better. – Michael Aug 12 '21 at 14:01