Samuele B.
Samuele B.

Reputation: 658

Generic type container in Java

Let's say I want to create a generic type container in Java, using an interface like this:

public interface GenericDataContainer<T>

I want classes that'll implement this interface to have an underlying structure to hold data of type T. However, I also want to keep track of who a piece of data was added by. In the GenericDataContainer interface, a method to add an object to the container might have a declaration like this:

public void put(String added_by, T obj);

I am just getting started with generics, and also Java in general, so I'm not sure what the best way to go about this would be.

Let's say I have a structure, like a HashMap that keeps track of what users I have, and let's say I identify users by their name String. How would I go about associating a T object inside my container to the String of the user who added it?

Would I wrap the object into a wrapper class that has two members:

T obj;
String added_by;

or is there a better way?

Let's say I also want to be able to allow certain users to access the object, not just the owner; could I just add an array of Strings to such wrapper object to keep track of users who were granted access?

This is what the whole interface specification is like (please don't critique it: I have no control over the specification)

public interface SecureDataContainer<T>{
    public void createUser(String id, String passw);
    
    // number of elements added by owner
    public int getSize(String owner, String passw);
    
    public boolean put(String owner, String passw, T data);

    public T get(String owner, String passw, T data);

    public T remove(String owner, String passw, T data);
    
    public void copy(String owner, String passw, T data);
    
    // enable another user to access the object
    public void share(String owner, String passw, String other, T data);

    public Iterator<T>getIterator(String owner, String passw);
}

Upvotes: 1

Views: 1708

Answers (3)

dustinroepsch
dustinroepsch

Reputation: 1160

If a user can only ever add a single object to your collection, then a Map<String, T> would suffice.

Then your put method is literally just the built in Map put. myMap.put(ownerString, dataOfTypeT)

If you want a single user to be able to add multiple data to your collection, then you want to create a Map<String,List<T>>.

Then your put method needs to create the list first if it doesn't already exist, otherwise it's the same.

class MyContainer<T> {
   private Map<String, List<T>> backingMap = new HashMap<>();

   public void put(String userName, T data) {
     if (!map.containsKey(userName)) {
        map.put(userName, new ArrayList<>());
     }
     map.get(userName).add(data);
   }

   public List<T> getAllData(String userName) {
      if (!map.get(userName)) {
         // in my opinion it makes more sense to return empty list than null
         return List.of() 
      }
      // making a copy is a good idea so that the caller can't modify our list. 
      return List.copyOf(map.get(userName)) 

   }
}

If you are okay with using a third party library, guava's ListMultimap provides similar behavior.

Upvotes: 0

Amir Afghani
Amir Afghani

Reputation: 38531

Let's say I have a structure, like a HashMap that keeps track of what users I have, and let's say I identify users by their name String. How would I go about associating a T object inside my container to the String of the user who added it?

What's wrong with :

import java.util.HashMap;
import java.util.Map;

interface GenericDataContainer<T> {
    public void put(String added_by, T obj);
}

class HashMapBasedContainer<T> implements GenericDataContainer<T> {

    //if this lives somewhere else, make sure it's accessible from here
    Map<String, T> mapper = new HashMap<>();

    @Override
    public void put(String added_by, T obj) {
        this.mapper.put(added_by, obj);
    }
}

Let's say I also want to be able to allow certain users to access the object, not just the owner; could I just add an array of Strings to such wrapper object to keep track of users who were granted access?

You could implement the interface again in a version that does exactly that.

Upvotes: 0

GhostCat
GhostCat

Reputation: 140427

What you outlined makes sense, you could do something like:

public class OwnedData<T> {
  private final OwnerId owner;
  private final T data;

  // constructor taking owner/data ... getters maybe

} 

(Note: it makes more sense to have a distinct type that denotes Owners, you might have two different users named "Carl", so better prepare yourself to be not rely just on a String name to identify owners)

But yes, that would be one way to go about this. Of course, you then have to think to correctly implement equals() and hashCode() for that class, to ensure that objects can be clearly distinguished.

Yet, in the real world, things are of course much more complicated. Permission models are complicated. You have to think not only about users, but also about "roles". Or groups of users. Or some data being read-only, some data being read/writeable.

In other words: there are many different requirements that a permission system might have to fulfil. Therefore we can't tell you what is best for you, as nobody here knows your specific requirements!

Upvotes: 2

Related Questions