Append java static variables

Viewed 207

I want to append list of elements to next list array, here are code example:

public class AuthoritiesConstant {

    public static List<String> USER_ROLES = Arrays.asList("authenticated", "user", "article:read", "article:offer");
    public static List<String> MODERATOR = Arrays.asList( "moderator", "article:create", "article:update", "article:approve");
    public static List<String> ADMIN_ROLES = Arrays.asList("admin", "article:delete");


    AuthoritiesConstant() {
        // Each role get previous role authorities
        MODERATOR.addAll(USER_ROLES);
        ADMIN_ROLES.addAll(MODERATOR);
    }
}

When I use in code ADMIN_ROLES variable only two roles are registered: "admin", "article:delete".

How can I append roles from previous role to next. So that moderator has all user roles, and administrator all moderator roles?

2 Answers

tl;dr

    public static final List < String > USER_ROLES, MODERATOR_ROLES, ADMIN_ROLES;

    static
    {
        USER_ROLES = List.of( "authenticated" , "user" , "article:read" , "article:offer" );

        List < String > mod = new ArrayList <>( USER_ROLES );
        mod.addAll( List.of( "moderator" , "article:create" , "article:update" , "article:approve" ) );
        MODERATOR_ROLES = List.copyOf( mod );

        List < String > admin = new ArrayList <>( MODERATOR_ROLES );
        admin.addAll( List.of( "admin" , "article:delete" ) );
        ADMIN_ROLES = List.copyOf( admin );
    }

Cannot add to fixed-size list

As khelwood commented, the Arrays.asList returns a fixed-size list. You cannot add or delete elements.

We have a more modern alternative for a compact literal declaration of a unmodifiable list in Java 9 and later: List.of.

List < String > furryAnimals = List.of( "dog" , "cat" ) ;
List< String > featheredAnimals = List.of( "cockatiel" , "canary" ) ;

You can make a modifiable list from those unmodifiable lists by passing them to the constructor and methods of other List implementations.

Here we instantiate a modifiable ArrayList object. In the constructor we pass one unmodifiable list. Then we add the contents of a second unmodifiable list by passing to addAll method.

List< String > allCreaturesGreatAndSmall = new ArrayList<>( furryAnimals ) ;
allCreaturesGreatAndSmall.addAll( featheredAnimals ) ;

You can make an unmodifiable list by passing the modifiable one to List.copyOf in Java 10 and later.

List < String > animals = List.copyOf( allCreaturesGreatAndSmall ) ;  // Make an unmodifiable list of a modifiable list. 

See also the correct Answer by M A for other issues.

By the way, in Java conventions, we use all-uppercase only for constants. Your lists are changing, so names such as USER_ROLES should be userRoles.

Constants

If you did indeed intend for those lists to be constants, those lists should be:

  • Unmodifiable
  • Declared final so no other object can be later assigned.

Your code might look something like the following.

package work.basil.example;

import java.util.ArrayList;
import java.util.List;

public class Authority
{
    public static final List < String > USER_ROLES, MODERATOR_ROLES, ADMIN_ROLES;

    static
    {
        USER_ROLES = List.of( "authenticated" , "user" , "article:read" , "article:offer" );

        List < String > mod = new ArrayList <>( USER_ROLES );
        mod.addAll( List.of( "moderator" , "article:create" , "article:update" , "article:approve" ) );
        MODERATOR_ROLES = List.copyOf( mod );

        List < String > admin = new ArrayList <>( MODERATOR_ROLES );
        admin.addAll( List.of( "admin" , "article:delete" ) );
        ADMIN_ROLES = List.copyOf( admin );
    }

    public static void main ( String[] args )
    {
        System.out.println( "USER_ROLES = " + USER_ROLES );
        System.out.println( "MODERATOR_ROLES = " + MODERATOR_ROLES );
        System.out.println( "ADMIN_ROLES = " + ADMIN_ROLES );
    }
}

When run.

USER_ROLES = [authenticated, user, article:read, article:offer]
MODERATOR_ROLES = [authenticated, user, article:read, article:offer, moderator, article:create, article:update, article:approve]
ADMIN_ROLES = [authenticated, user, article:read, article:offer, moderator, article:create, article:update, article:approve, admin, article:delete]

As mentioned in the comments, the lists are static members, so the user of your class is not expected to invoke the constructor, hence will not see the modifications to the lists (and in any case the modification of adding elements will throw an error because Arrays.asList returns a fixed-size list).

You can do the concatenation inline with the member declarations, using the stream API to concatenate two lists:

public static List<String> MODERATOR = Stream.concat(USER_ROLES.stream(),
            Arrays.asList( "moderator", "article:create", "article:update", "article:approve").stream())
            .collect(Collectors.toUnmodifiableList());
public static List<String> ADMIN_ROLES = Stream.concat(MODERATOR.stream(),
            Arrays.asList("admin", "article:delete").stream())
            .collect(Collectors.toUnmodifiableList());
Related