Mixture of class and enum features - java

I have a situation where I define security roles for an organization. The choices are a set of known enumerated default values, and the possibility of any number of custom role. The roles define the permissions the employees have in the organization. For example, a user can be;
public enum Role
{
Owner, Administrator, User, Guest;
}
However, the organization could also want its own custom roles (e.g. A PowerUser). I am looking for the best way to declare an object that has a known enumerated list of values (thats an enum) but with the possibility of provide any number of custom values (thats a class).
A naive approach would be the following (adding a custom enum value):
public enum Role
{
Owner, Administrator, User, Guest, Custom;
public BaseRole asRole()
{
//switch statement returning the BaseRole depending on the enum value.
}
}
public class BaseRole
{
Set<Permission> permissions;
}
The problem with this option is that the glue code will became very verbose if the enum value custom is selected. Since the custom value which holds all possible custom role would behave differently that the other values, every function that accepts a Role will need special glue to handle custom.
Ideally, something like this would probably be the best:
public enum Role
{
Owner, Administrator, User, Guest, Set<Custom>;
}
edit:
for reference, the user class would be
public class User
{
Set<Role> roles;
}

A possible solution would be to look back in pseudo-enum implementations in the pre enum Java versions. E.g.:
public class Role {
public static final Role OWNER = new Role("OWNER");
public static final Role ADMIN = new Role("ADMIN");
public static final Role USER = new Role("USER");
public static final Role GUEST = new Role("GUEST");
private String name;
// getter, setter, constructor, toString(), hashCode(), equals()
}
So whenever a Role is required, you can use the final fields:
Role r = Role.OWNER;
And still define custom ones:
Role r = new Role("Cook");
With some caution, it may even allow for == equality checking between a variable and the predefined values, but I would advise against it (use equals() always).

Maybe what you're looking for is an EnumSet?
http://docs.oracle.com/javase/7/docs/api/java/util/EnumSet.html

This is the solution I went with.
public interface Role
{
String getName();
}
public enum StandardRole implements Role
{
Owner, Administrator, User, Guest;
#Override
public String getName()
{
return this.name();
}
}
public class CustomRole implements Role
{
private String name;
public CustomRole(String name)
{
this.name = name;
}
#Override
public String getName()
{
return this.name;
}
}
public class User
{
Set<Role> roles;
}

Related

Implement filter for Enum to check value before insert

I want to store available user roles into Enum:
public enum Role implements GrantedAuthority {
ROLE_ADMIN, ROLE_CLIENT;
public String getAuthority() {
return name();
}
}
Entity value:
#Column(length = 25)
#Enumerated(EnumType.STRING)
private Role role;
I create new user using the code:
Users user = new Users();
user.setRole(Role.valueOf("ROLE_ADMIN"));
Is there someway to make a check is ROLE_ADMIN a valid Enum value because I can break the code it's not a valid value.
You can create an specific method in your enum to know if the provided string matches or not with an specific one. Something like:
public static Optional<Role> getFromString(String valueToCheck) {
return Optional.ofNullable(valueToCheck)
.flatMap(toCheck -> Arrays.stream(Role.values())
.filter(r -> toCheck.equals(r.name()))
.findFirst());
}
Or use another approaches of the above one:
Change Optional<Role> by Role and use .orElse(null).
Change Optional<Role> by Role and use .orElseThrow(...) to throw an exception.

Decide which Enum return based on object properties

I'm wondering if there is some design pattern to help me with this problem.
Let's say I have a class Person which has three attributes: name, nickname and speaksEnglish and an Enum PersonType with TypeOne, TypeTwo and TypeThree.
Let's say if a Person has nickname and speaksEnglish it's a TypeOne. If it has nickame but doesn't speaksEnglish, it's a TypeTwo. If it does not have nickame, so it's TypeThree.
My first thought would have a method with some if-else and returning the related Enum. In the future I can have more attributes in Person and other types of PersonType to decide.
So, my first thought was create a method with a bunch of if (...) { return <PersonType> } or switch-case, but I was wondering if there is some design pattern I can use instead of ifs and switch-case.
I will recomend you to use just simple inheritance with immutable objects.
So, at first you have to create abstract class:
public abstract class AbstractPerson {
private final String name;
private final Optional<String> nickname;
private final boolean speaksEnglish;
private final PersonType personType;
protected AbstractPerson(final String name, final Optional<String> nickname, final boolean speaksEnglish, final PersonType personType) {
this.name = name;
this.nickname = nickname;
this.speaksEnglish = speaksEnglish;
this.personType = personType;
}
public String getName() {
return name;
}
public Optional<String> getNickname() {
return nickname;
}
public boolean getSpeaksEnglish() {
return speaksEnglish;
}
public PersonType getPersonType() {
return personType;
}
}
With PersonType enum:
public enum PersonType {
TypeOne, TypeTwo, TypeThree;
}
Now, we have three options with corresponding constructors in child classes:
public final class EnglishSpeakingPerson extends AbstractPerson {
public EnglishSpeakingPerson(final String name, final String nickname) {
super(name, Optional.of(nickname), true, PersonType.TypeOne);
}
}
public final class Person extends AbstractPerson {
public Person(final String name, final String nickname) {
super(name, Optional.of(nickname), false, PersonType.TypeTwo);
}
public Person(final String name) {
super(name, Optional.empty(), false, PersonType.TypeThree);
}
}
In this case, our concrete classes are immutable and its type is defined in moment of creation. You don't need to create if-else ladders - if you want to create new type, just create new class/constructor.
I don't think Type can really be an attribute of a Person. I am not against #ByeBye's answer but with that implementation you will still end up changing Person class when there are new types introduced.
X type of person is ultimately a person itself. Say a Manager or Developer are both employees of a company, so it makes a lot of sense to have them as specialized classes that derive from an Employee. Similarly in your case, having person type as an attribute and then doing all if-else stuff clearly violates SOLID.
I would instead have specific implementations of Person class and mark itself as an abstract one.
public abstract class Person {
public Person(string name) {
Name = name;
}
public abstract string Name { get; set; }
public abstract string NickName { get; set; }
public abstract bool SpeaksEnglish { get; set; }
}
public class TypeOnePerson : Person {
public TypeOnePerson(string name, string nickName) : base(name) {
NickName = nickName; // Validate empty/ null
}
SpeaksEnglish = true;
}
public class TypeTwoPerson : Person {
public TypeOnePerson(string name, string nickName) : base(name) {
NickName = nickName; // Validate empty/ null
}
SpeaksEnglish = false;
}
I also think that this question is language-agnostic, it is a pure design question. So please bear with me as the code above is in C#. That doesn't matter, however.
As far as OO principles are considered why to create object with combinations of optional attributes? If its question of one or two then Optional approach will remain maintainable, but type will be based on many combinations (in future code will be full of Boolean Algebra) and question also says "...In the future I can have more attributes in Person and other types of PersonType to decide.".
I would suggest approach of using Decorator pattern, which allows us to create customized objects with complete code reuse. Person will be Component and Optional attributes (they are types e.g NickName with validation as behavior) will be concrete decorators.
Any addition to Person and adding new Concrete Decorator type remain two separate concerns. Decorator Pattern is a best candidate for this kind of requirement. Its Intent from GOF book (by Erich gamma) pattern Catalog says - "Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality". [though for very small number of expected extensions earlier answers make more sense.]

Java - How to convert a String into specific enum implementing an interface

Consider below inner Enum implementing an interface:
public interface NotificationTypes {
public enum CONTACT_LIST implements NotificationTypes{
ADDED("CONTACT_LIST-ADDED"),
REMOVED("CONTACT_LIST-REMOVED");
public enum INVITATION implements NotificationTypes{
ACCEPTED("CONTACT_LIST-INVITATION-ACCEPTED"),
REJECTED("CONTACT_LIST-INVITATION-REJECTED");
String name = "";
private INVITATION(String name){
this.name = name;
}
public String getName(){
return name;
}
};
String name = "";
private CONTACT_LIST(String name){
this.name = name;
}
public String getName(){
return name;
}
}
public String getName();
}
Now consider that data in database/mongodb is stored in the form of String for NotificationTypes in a table/document.
{
"_id" : ObjectId("59882ba49e5d82c72ba44fde"),
"template" : "Contact list Invitation accepted by your friend",
"type" : "CONTACT_LIST-INVITATION-ACCEPTED"
}
So my question is: How to convert that string back into specific enum at runtime without knowing exactly the name of enum to be mapped?
Domain class is looks like this:
#Document(collection = CollectionNames.XXX_TEMPLATE)
public class XXXTemplate {
private NotificationTypes type;
//Other parameters, getters & setters + Constructor
}
I'd build a Map<String, NotificationTypes> and populate that with all instances you have. You can then look up from that map.
I don't think the compiler can help you a lot with keeping that in sync, other than that you can loop over EnumType.values() (but you have to remember to do it for all of your enum types).
How to convert that string back into specific enum at runtime without knowing exactly the name of enum to be mapped?
Via Enum.valueOf().
Basically just building on #Thilo's answer, but perhaps a more 'Springified' way if it's something that you'd want - you could define a #Bean in your config that contains all your enum values, like:
#Configuration
public class Config {
#Bean
public List<NotificationTypes> notificationTypes() {
List<NotificationTypes> notificationTypes = new ArrayList<>();
notificationTypes.addAll(Arrays.asList(NotificationTypes.CONTACT_LIST.values()));
notificationTypes.addAll(Arrays.asList(NotificationTypes.CONTACT_LIST.INVITATION.values()));
return notificationTypes;
}
}
And then #Autowire this #Bean into a parser to do the actual matching of String to enum, something like:
#Component
public class NotificationTypeParser {
#Autowired
private List<NotificationTypes> notificationTypes;
public NotificationTypes parseNotificationType(String type) {
for (NotificationTypes notificationType : notificationTypes) {
if (notificationType.getName().equals(type)) {
return notificationType;
}
}
return null;
}
}
Obviously you probably want something better than just returning null if the enum isn't found, and you could potentially do something smarter in the #Bean definition to validate that the enums all have different names, etc. Or, conceivably, use reflection in there to find all the implementations of NotificationTypes.
I'm not sure that this really gives you any additional benefits over just storing all the possible values in a Map, but, as I say, I suppose it's a bit Spring-ier.

How to create typesafe user roles for Spring Security?

I'd like to make use of spring-security with ROLE_ADMIN and ROLE_USER roles.
I therefore try to create a typesafe enum class, but the #Secured annotation requires a constant String, which I cannot achieve by using an enum class.
What could I change in the following code?
public enum UserRole {
ADMIN("ROLE_ADMIN");
private String role;
public UserRole(String role) {
this.role = role;
}
}
//error: The value for annotation attribute Secured.value must be a constant expression
#Secured(USerRole.ADMIN.value())
public class SecuredView {
}
This question is a bit old, but this is my take on it:
public enum Role implements GrantedAuthority {
ROLE_USER, ROLE_ADMIN;
#Override
public String getAuthority() {
return name();
}
}
You can then use this together with #PreAuthorize and Spring Expression Language to authorize your methods and classes like so:
#PreAuthorize("hasRole(T(<package name>.Role).ROLE_ADMIN)")
public void doSomeThing() {
...
}
Note: The package name has to be the entire package name (org.company.project) and without the < and >.
As you can see, this isn't type safe per definition, as SpEL expressions are still strings, but IDEs like IntelliJ recognizes them, and will let you know of any errors.
You can use #PreAuthorize with multiple roles using hasAnyRole().
Of course, this may become a bit verbose with many roles, but you can make it prettier by creating your own annotation like this:
#Target({ ElementType.METHOD, ElementType.TYPE })
#Retention(RetentionPolicy.RUNTIME)
#Inherited
#PreAuthorize("hasRole(T(<package name>.Role).ROLE_ADMIN)")
public #interface AdminAuthorization {
}
Following this, you can authorize your methods like so:
#AdminAuthorization
public void doSomething() {
...
}
Partial solution:
public enum Role implements GrantedAuthority {
ADMIN(Code.ADMIN),
USER(Code.USER);
private final String authority;
Role(String authority) {
this.authority = authority;
}
#Override
public String getAuthority() {
return authority;
}
public class Code {
public static final String ADMIN = "ROLE_ADMIN";
public static final String USER = "ROLE_USER";
}
}
Results in:
#Secured(Role.Code.ADMIN)
If you are using Lombok you can use the #FieldNameConstants annotation:
#FieldNameConstants
public class UserRoles {
private String ROLE_USER, ROLE_ADMIN;
}
And then use it like this:
#Secured(UserRoles.Fields.ROLE_ADMIN)
Maybe in the future, there will be the #EnumNameConstants annotation, which would fit even better.

What's the most object-oriented way to design an address book?

I am asking myself how to design an object-oriented address book in Java.
Let's say a contact can have several contact details, like addresses, phone numbers and e-mail addresses.
One way to implement this would be to give every contact an ArrayList for every type. But there must be a better and more object-oriented solution. What is it?
The most OOP suggestion I can give you is to create a class for every item/piece of information. For example:
public abstract class ContactInfo { /* ... */ }
public class Address extends ContactInfo { /* ... */ }
public class PhoneNumber extends ContactInfo { /* ... */ }
public class EmailAddress extends ContactInfo { /* ... */ }
public class Contact {
private String name;
private Set<ContactInfo> info;
// ...
}
and finally,
public class AddressBook {
List<Contact> contacts;
// ...
}
This may or may not be overkill for your specific case, but as a thought experiment, it's the way to go. It obviously takes care of the literal part of OOP — using objects — but also lays groundwork for encapsulation, abstraction and inheritance, which are closely related principles.
You're on the right track. The only thing I would do differently would be to use a List interface instead of an ArrayList collection to reference the contacts' attribute collections. This is advice based on the code-to-interfaces rule-of-thumb as described in this article and many others.
I don't think that's particularly un-object oriented. If your domain is such that a Person can have zero or more EmailAddresses, then you've almost exactly described the situation to use a list.
The only alternative approach I can think of would be to have fields such as
WorkEmail
PersonalEmail
OtherEmail1
OtherEmail2
OtherEmail3
but in my opinion that's worse, because:
You simply cannot support more than five email addresses (well, you could add more fields, but that increases the pain of the latter points and still imposes some finite limit.)
You're implying some extra semantics than may be present (what if the same address is used for work and personal? What if neither applies, can you just fill the Other ones? What if you don't know the purpose?)
You now have to test each field manually to see which is null, which is going to involve a non-trivial amount of duplication in Java. You can't use nice features like the enhanced-for loop to apply the same block to every email address, and you can't trivially count how many addresses there are
The list of properties that a Person has is now much less clean. I suppose you could package these properties into an EmailContactDetails class or something, but now you've got an extra level of indirection (more conceptual complexity) for no real gain.
So, if a person has a possibly-empty, unbounded list of email addresses, what's wrong with representing that as a list?
You can also use a Map, and then get specific values e.g. via myMap.get("emailAdress1") or iterate over the whole map like you would do with a list via myMap.entrySet().
One simple way to handle most of the use cases can be like this
public class AddressBook {
private Map<String, Contact> contacts;
AddressBook(){
contacts = new HashMap<String, Contact>();
}
public boolean addContact(Contact contact) {
if(contacts.containsKey(contact.getName())) {
System.out.println("Already exists");
return false;
}
contacts.put(contact.getName(), contact);
return true;
}
public boolean updateContact(Contact contact) {
contacts.put(contact.getName(), contact);
return true;
}
}
class Contact{
private String name;
private String email;
private String phone;
private Address address;
public Contact(String name) {
this.name = name;
}
public Contact(String name, String email, String phone, Address address) {
this.name = name;
this.email = email;
this.phone = phone;
this.address = address;
}
// getters and setters
#Override
public String toString() {
return "name is "+name+" and address is "+address;
}
}
class Address{
private String street1;
private String street2;
private String city;
private int zipcode;
public Address() {}
// getters and setters
#Override
public String toString() {
return "street1 is "+street1+" and zipcode is "+zipcode;
}
}

Categories