Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala converters convert Java collections to Wrapper objects

I have a scala function which returns a util.Map[String], util.Set[String].

def getAcls(): Map[String, Set[String]] = {
((for (groupRole: GroupRoleAccess <- groupRoleAccess;
     user <- groupService.getGroup(groupRole.groupId).getUsers;
     permissions = roleService.getRole(groupRole.roleId)  .getPermissions)
  yield user.getUserId -> permissions).groupBy(_._1).map { case (k,v) => (k, v.flatMap(_._2).asJava)})
}

I am simply calling this method on a set of these objects to get a util.Set[util.Map[String], util.Set[String]].

var unevaluatedacls = for (aclTemplate <- aclTemplates)
  yield aclTemplate.getAcls

When I inspect unevaluatedacls, I see that it is of the type HashSet. But its elements are of the type Wrappers$MapWrapper instead of util.Map. As a result of this, I am unable to persist this object. I cannot understand this behavior. When I try

var unevaluatedacls = (for (aclTemplate <- aclTemplates)
  yield aclTemplate.getAcls).asJava

the unevaluatedacls also changes to Wrapper$SetWrapper. Is it because I am somehow trying to convert immutable scala collections to java collections? I know that only mutable scala collections are compatible to be converted to corresponding java collections using JavaConverters

like image 241
rrrocky Avatar asked Jul 17 '16 15:07

rrrocky


1 Answers

JavaConverters convert containers to/from java "in place", without copying the data. That is, if you have a scala Map, and convert it to java, it's not going to create a whole new container, and copy all of the data over to it. Instead, it just returns a wrapper class, that implements the java's Map interface, but is backed by the original data rather than a copy.

This is a good thing, because it save both memory and time.

The whole idea of interfaces is that the user is not supposed to care about the particular implementation behind it. "Coding to interface" is the idea. Finding yourself caring about the actual implementation classes is usually (not always, but often) a smell of bad design.

If you have to have your data copied into a container, that's an instance of a particular class, you'll have to do it explicitly:

val javaMap = new HashMap[String, Set[String]](wrappedMap)

Better yet, consider not using java serialization in the first place. It's slow, buggy, tedious, dangerous ... and forces you jump through million weird hoops like this. There is a whole lot of better alternatives out there nowadays.

like image 178
Dima Avatar answered Oct 02 '22 16:10

Dima