This is an automated email from the ASF dual-hosted git repository.

ilgrosso pushed a commit to branch 4_0_X
in repository https://gitbox.apache.org/repos/asf/syncope.git


The following commit(s) were added to refs/heads/4_0_X by this push:
     new 95fa928ffe [SYNCOPE-1944] Fixing derived attribute management for 
memberships
95fa928ffe is described below

commit 95fa928ffe08e016c1b9b566770093ff6f49a852
Author: Francesco Chicchiriccò <[email protected]>
AuthorDate: Thu Jan 15 16:38:38 2026 +0100

    [SYNCOPE-1944] Fixing derived attribute management for memberships
---
 .../core/provisioning/api/DerAttrHandler.java      | 44 ++++++-------
 .../provisioning/api/jexl/JexlContextBuilder.java  |  5 +-
 .../core/provisioning/api/jexl/JexlUtilsTest.java  | 10 +--
 .../provisioning/java/DefaultDerAttrHandler.java   | 75 +++++++++++-----------
 .../provisioning/java/DefaultMappingManager.java   |  8 ++-
 .../core/provisioning/java/data/AnyDataBinder.java |  9 ++-
 .../java/data/RealmDataBinderImpl.java             |  2 +-
 .../java/DefaultMappingManagerTest.java            |  9 ++-
 .../apache/syncope/fit/core/MembershipITCase.java  | 27 ++++++++
 9 files changed, 110 insertions(+), 79 deletions(-)

diff --git 
a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
 
b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
index f9863946a9..c1f82867a8 100644
--- 
a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
+++ 
b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/DerAttrHandler.java
@@ -28,30 +28,21 @@ import org.apache.syncope.core.persistence.api.entity.Realm;
 public interface DerAttrHandler {
 
     /**
-     * Calculates derived attribute value associated to the given realm, for 
the given derived schema.
+     * Calculates derived attributes values associated to the given realm.
      *
      * @param realm realm
-     * @param schema derived schema
-     * @return derived attribute value
+     * @return derived attribute values
      */
-    String getValue(Realm realm, DerSchema schema);
+    Map<String, String> getValues(Realm realm);
 
     /**
-     * Calculates derived attribute value associated to the given any, for the 
given derived schema.
+     * Calculates derived attribute value associated to the given realm, for 
the given derived schema.
      *
-     * @param any any object
+     * @param realm realm
      * @param schema derived schema
      * @return derived attribute value
      */
-    String getValue(Any any, DerSchema schema);
-
-    /**
-     * Calculates derived attributes values associated to the given realm.
-     *
-     * @param realm realm
-     * @return derived attribute values
-     */
-    Map<DerSchema, String> getValues(Realm realm);
+    String getValue(Realm realm, DerSchema schema);
 
     /**
      * Calculates derived attributes values associated to the given any.
@@ -59,25 +50,34 @@ public interface DerAttrHandler {
      * @param any any object
      * @return derived attribute values
      */
-    Map<DerSchema, String> getValues(Any any);
+    Map<String, String> getValues(Any any);
 
     /**
-     * Calculates derived attribute value associated to the given any, for the 
given membership and
-     * derived schema.
+     * Calculates derived attribute value associated to the given any, for the 
given derived schema.
      *
      * @param any any object
-     * @param membership membership
      * @param schema derived schema
      * @return derived attribute value
      */
-    String getValue(Any any, Membership<?> membership, DerSchema schema);
+    String getValue(Any any, DerSchema schema);
 
     /**
      * Calculates derived attributes values associated to the given any, for 
the given membership.
      *
-     * @param any any object
+     * @param groupable user or any object
      * @param membership membership
      * @return derived attribute values
      */
-    Map<DerSchema, String> getValues(Groupable<?, ?, ?> any, Membership<?> 
membership);
+    Map<String, String> getValues(Groupable<?, ?, ?> groupable, Membership<?> 
membership);
+
+    /**
+     * Calculates derived attribute value associated to the given any, for the 
given membership and
+     * derived schema.
+     *
+     * @param groupable user or any object
+     * @param membership membership
+     * @param schema derived schema
+     * @return derived attribute value
+     */
+    String getValue(Groupable<?, ?, ?> groupable, Membership<?> membership, 
DerSchema schema);
 }
diff --git 
a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/jexl/JexlContextBuilder.java
 
b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/jexl/JexlContextBuilder.java
index 269ec784e8..bed2130497 100644
--- 
a/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/jexl/JexlContextBuilder.java
+++ 
b/core/provisioning-api/src/main/java/org/apache/syncope/core/provisioning/api/jexl/JexlContextBuilder.java
@@ -41,7 +41,6 @@ import org.apache.syncope.common.lib.to.AnyTO;
 import org.apache.syncope.common.lib.to.RealmTO;
 import org.apache.syncope.core.persistence.api.entity.Any;
 import org.apache.syncope.core.persistence.api.entity.Attributable;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.PlainAttr;
 import org.apache.syncope.core.persistence.api.entity.Realm;
 import org.apache.syncope.core.persistence.api.utils.FormatUtils;
@@ -187,13 +186,13 @@ public class JexlContextBuilder {
     }
 
     public JexlContextBuilder derAttrs(final Attributable attributable, final 
DerAttrHandler derAttrHandler) {
-        Map<DerSchema, String> derAttrs = attributable instanceof Realm realm
+        Map<String, String> derAttrs = attributable instanceof Realm realm
                 ? derAttrHandler.getValues(realm)
                 : attributable instanceof Any any
                         ? derAttrHandler.getValues(any)
                         : Map.of();
 
-        derAttrs.forEach((schema, value) -> jexlContext.set(schema.getKey(), 
value));
+        derAttrs.forEach((schema, value) -> jexlContext.set(schema, value));
 
         return this;
     }
diff --git 
a/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/jexl/JexlUtilsTest.java
 
b/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/jexl/JexlUtilsTest.java
index 5ccaad0c27..39cae5985f 100644
--- 
a/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/jexl/JexlUtilsTest.java
+++ 
b/core/provisioning-api/src/test/java/org/apache/syncope/core/provisioning/api/jexl/JexlUtilsTest.java
@@ -147,8 +147,8 @@ public class JexlUtilsTest extends AbstractTest {
 
         String expression = null;
 
-        Map<DerSchema, String> derAttrs = new HashMap<>();
-        derAttrs.put(derSchema, expression);
+        Map<String, String> derAttrs = new HashMap<>();
+        derAttrs.put("derSchema", expression);
 
         when(derAttrHandler.getValues(any(Any.class))).thenReturn(derAttrs);
 
@@ -156,7 +156,7 @@ public class JexlUtilsTest extends AbstractTest {
         ReflectionTestUtils.setField(builder, "jexlContext", context);
 
         builder.derAttrs(any, derAttrHandler);
-        verify(context).set(derAttrs.get(derSchema), expression);
+        verify(context).set("derSchema", expression);
     }
 
     @Test
@@ -168,8 +168,8 @@ public class JexlUtilsTest extends AbstractTest {
 
         String expression = null;
 
-        Map<DerSchema, String> derAttrs = new HashMap<>();
-        derAttrs.put(derSchema, expression);
+        Map<String, String> derAttrs = new HashMap<>();
+        derAttrs.put("derSchema", expression);
 
         when(any.getPlainAttrs()).thenReturn(new ArrayList<>());
         when(derAttrHandler.getValues(any(Any.class))).thenReturn(derAttrs);
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
index edd822dc7a..5497ceb3a7 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultDerAttrHandler.java
@@ -52,11 +52,11 @@ public class DefaultDerAttrHandler implements 
DerAttrHandler {
         this.jexlTools = jexlTools;
     }
 
-    protected Map<DerSchema, String> getValues(
+    protected Map<String, String> getValues(
             final Attributable attributable,
             final Collection<? extends DerSchema> schemas) {
 
-        Map<DerSchema, String> result = new HashMap<>(schemas.size());
+        Map<String, String> result = new HashMap<>(schemas.size());
 
         schemas.forEach(schema -> {
             JexlContext jexlContext = new JexlContextBuilder().
@@ -64,12 +64,20 @@ public class DefaultDerAttrHandler implements 
DerAttrHandler {
                     fields(attributable).
                     build();
 
-            result.put(schema, 
jexlTools.evaluateExpression(schema.getExpression(), jexlContext).toString());
+            result.put(schema.getKey(), 
jexlTools.evaluateExpression(schema.getExpression(), jexlContext).toString());
         });
 
         return result;
     }
 
+    @Override
+    public Map<String, String> getValues(final Realm realm) {
+        return getValues(
+                realm,
+                realm.getAnyTypeClasses().stream().
+                        flatMap(atc -> 
atc.getDerSchemas().stream()).collect(Collectors.toSet()));
+    }
+
     @Override
     public String getValue(final Realm realm, final DerSchema schema) {
         if (realm.getAnyTypeClasses().stream().flatMap(atc -> 
atc.getDerSchemas().stream()).anyMatch(schema::equals)) {
@@ -77,50 +85,32 @@ public class DefaultDerAttrHandler implements 
DerAttrHandler {
             return null;
         }
 
-        return getValues(realm, Set.of(schema)).get(schema);
+        return getValues(realm, Set.of(schema)).get(schema.getKey());
     }
 
     @Override
-    public String getValue(final Any any, final DerSchema schema) {
-        if (!anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, 
DerSchema.class).forSelfContains(schema)) {
-            LOG.debug("{} not allowed for {}", schema, any);
-            return null;
-        }
-
-        return getValues(any, Set.of(schema)).get(schema);
+    public Map<String, String> getValues(final Any any) {
+        return getValues(
+                any,
+                anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, 
DerSchema.class).getForSelf());
     }
 
     @Override
-    public String getValue(final Any any, final Membership<?> membership, 
final DerSchema schema) {
-        if (!anyUtilsFactory.getInstance(any).dao().
-                findAllowedSchemas(any, 
DerSchema.class).getForMembership(membership.getRightEnd()).contains(schema)) {
-
+    public String getValue(final Any any, final DerSchema schema) {
+        if (!anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, 
DerSchema.class).forSelfContains(schema)) {
             LOG.debug("{} not allowed for {}", schema, any);
             return null;
         }
 
-        return getValues(any, Set.of(schema)).get(schema);
+        return getValues(any, Set.of(schema)).get(schema.getKey());
     }
 
-    @Override
-    public Map<DerSchema, String> getValues(final Realm realm) {
-        return getValues(
-                realm,
-                realm.getAnyTypeClasses().stream().
-                        flatMap(atc -> 
atc.getDerSchemas().stream()).collect(Collectors.toSet()));
-    }
+    protected Map<String, String> getValues(
+            final Groupable<?, ?, ?> groupable,
+            final Membership<?> membership,
+            final Set<DerSchema> schemas) {
 
-    @Override
-    public Map<DerSchema, String> getValues(final Any any) {
-        return getValues(
-                any,
-                anyUtilsFactory.getInstance(any).dao().findAllowedSchemas(any, 
DerSchema.class).getForSelf());
-    }
-
-    protected Map<DerSchema, String> getValues(
-            final Groupable<?, ?, ?> groupable, final Membership<?> 
membership, final Set<DerSchema> schemas) {
-
-        Map<DerSchema, String> result = new HashMap<>(schemas.size());
+        Map<String, String> result = new HashMap<>(schemas.size());
 
         schemas.forEach(schema -> {
             JexlContext jexlContext = new JexlContextBuilder().
@@ -128,18 +118,31 @@ public class DefaultDerAttrHandler implements 
DerAttrHandler {
                     fields(groupable).
                     build();
 
-            result.put(schema, 
jexlTools.evaluateExpression(schema.getExpression(), jexlContext).toString());
+            result.put(schema.getKey(), 
jexlTools.evaluateExpression(schema.getExpression(), jexlContext).toString());
         });
 
         return result;
     }
 
     @Override
-    public Map<DerSchema, String> getValues(final Groupable<?, ?, ?> any, 
final Membership<?> membership) {
+    public Map<String, String> getValues(final Groupable<?, ?, ?> any, final 
Membership<?> membership) {
         return getValues(
                 any,
                 membership,
                 anyUtilsFactory.getInstance(any).dao().
                         findAllowedSchemas(any, 
DerSchema.class).getForMembership(membership.getRightEnd()));
     }
+
+    @Override
+    public String getValue(final Groupable<?, ?, ?> groupable, final 
Membership<?> membership, final DerSchema schema) {
+        if (!anyUtilsFactory.getInstance(groupable).dao().
+                findAllowedSchemas(groupable, DerSchema.class).
+                getForMembership(membership.getRightEnd()).contains(schema)) {
+
+            LOG.debug("{} not allowed for {}", schema, groupable);
+            return null;
+        }
+
+        return getValues(groupable, membership, 
Set.of(schema)).get(schema.getKey());
+    }
 }
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
index 76b88c6baf..33b3b878ea 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/DefaultMappingManager.java
@@ -278,7 +278,11 @@ public class DefaultMappingManager implements 
MappingManager {
         String connObjectLink = orgUnit.getConnObjectLink();
         String evalConnObjectLink = null;
         if (StringUtils.isNotBlank(connObjectLink)) {
-            JexlContext jexlContext = new 
JexlContextBuilder().fields(realm).build();
+            JexlContext jexlContext = new JexlContextBuilder().
+                    fields(realm).
+                    plainAttrs(realm.getPlainAttrs()).
+                    derAttrs(realm, derAttrHandler).
+                    build();
 
             evalConnObjectLink = jexlTools.evaluateExpression(connObjectLink, 
jexlContext).toString();
         }
@@ -848,7 +852,7 @@ public class DefaultMappingManager implements 
MappingManager {
                         DerSchema derSchema = (DerSchema) 
intAttrName.getSchema();
                         String derValue = membership == null
                                 ? derAttrHandler.getValue(ref, derSchema)
-                                : derAttrHandler.getValue(ref, membership, 
derSchema);
+                                : derAttrHandler.getValue((Groupable<?, ?, ?>) 
ref, membership, derSchema);
                         if (derValue != null) {
                             PlainAttrValue attrValue = new PlainAttrValue();
                             attrValue.setStringValue(derValue);
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyDataBinder.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyDataBinder.java
index c14fcec373..dfe01d7f4f 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyDataBinder.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/AnyDataBinder.java
@@ -63,7 +63,6 @@ import org.apache.syncope.core.persistence.api.entity.AnyType;
 import org.apache.syncope.core.persistence.api.entity.AnyTypeClass;
 import org.apache.syncope.core.persistence.api.entity.AnyUtils;
 import org.apache.syncope.core.persistence.api.entity.AnyUtilsFactory;
-import org.apache.syncope.core.persistence.api.entity.DerSchema;
 import org.apache.syncope.core.persistence.api.entity.EntityFactory;
 import org.apache.syncope.core.persistence.api.entity.ExternalResource;
 import org.apache.syncope.core.persistence.api.entity.Groupable;
@@ -97,7 +96,7 @@ abstract class AnyDataBinder extends AttributableDataBinder {
             final String realmFullPath,
             final Collection<? extends AnyTypeClass> auxClasses,
             final Collection<PlainAttr> plainAttrs,
-            final Map<DerSchema, String> derAttrs,
+            final Map<String, String> derAttrs,
             final Collection<? extends ExternalResource> resources) {
 
         anyTO.setRealm(realmFullPath);
@@ -108,7 +107,7 @@ abstract class AnyDataBinder extends AttributableDataBinder 
{
                 add(new 
Attr.Builder(plainAttr.getSchema()).values(plainAttr.getValuesAsStrings()).build()));
 
         derAttrs.forEach((schema, value) -> anyTO.getDerAttrs().
-                add(new Attr.Builder(schema.getKey()).value(value).build()));
+                add(new Attr.Builder(schema).value(value).build()));
 
         
anyTO.getResources().addAll(resources.stream().map(ExternalResource::getKey).collect(Collectors.toSet()));
     }
@@ -131,7 +130,7 @@ abstract class AnyDataBinder extends AttributableDataBinder 
{
 
     protected static MembershipTO getMembershipTO(
             final Collection<PlainAttr> plainAttrs,
-            final Map<DerSchema, String> derAttrs,
+            final Map<String, String> derAttrs,
             final Membership<? extends Any> membership) {
 
         MembershipTO membershipTO = new 
MembershipTO.Builder(membership.getRightEnd().getKey()).
@@ -141,7 +140,7 @@ abstract class AnyDataBinder extends AttributableDataBinder 
{
                 add(new 
Attr.Builder(plainAttr.getSchema()).values(plainAttr.getValuesAsStrings()).build()));
 
         derAttrs.forEach((schema, value) -> membershipTO.getDerAttrs().
-                add(new Attr.Builder(schema.getKey()).value(value).build()));
+                add(new Attr.Builder(schema).value(value).build()));
 
         return membershipTO;
     }
diff --git 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
index ab9572e14c..aa99277b7a 100644
--- 
a/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
+++ 
b/core/provisioning-java/src/main/java/org/apache/syncope/core/provisioning/java/data/RealmDataBinderImpl.java
@@ -359,7 +359,7 @@ public class RealmDataBinderImpl extends 
AttributableDataBinder implements Realm
                 add(new 
Attr.Builder(plainAttr.getSchema()).values(plainAttr.getValuesAsStrings()).build()));
 
         derAttrHandler.getValues(realm).forEach((schema, value) -> 
realmTO.getDerAttrs().
-                add(new Attr.Builder(schema.getKey()).value(value).build()));
+                add(new Attr.Builder(schema).value(value).build()));
 
         if (admin) {
             
Optional.ofNullable(realm.getAccountPolicy()).map(AccountPolicy::getKey).
diff --git 
a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java
 
b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java
index 57d692715d..95561f9e71 100644
--- 
a/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java
+++ 
b/core/provisioning-java/src/test/java/org/apache/syncope/core/provisioning/java/DefaultMappingManagerTest.java
@@ -83,7 +83,7 @@ public class DefaultMappingManagerTest extends AbstractTest {
     public void prepareAttrsForUser() {
         User bellini = userDAO.findByUsername("bellini").orElseThrow();
         ExternalResource ldap = 
resourceDAO.findById("resource-ldap").orElseThrow();
-        Provision provision = 
ldap.getProvisionByAnyType(AnyTypeKind.USER.name()).get();
+        Provision provision = 
ldap.getProvisionByAnyType(AnyTypeKind.USER.name()).orElseThrow();
 
         assertNotEquals(CipherAlgorithm.AES, bellini.getCipherAlgorithm());
 
@@ -161,7 +161,7 @@ public class DefaultMappingManagerTest extends AbstractTest 
{
     public void prepareAttrsForLinkedAccount() {
         User vivaldi = userDAO.findByUsername("vivaldi").orElseThrow();
         ExternalResource ldap = 
resourceDAO.findById("resource-ldap").orElseThrow();
-        Provision provision = 
ldap.getProvisionByAnyType(AnyTypeKind.USER.name()).get();
+        Provision provision = 
ldap.getProvisionByAnyType(AnyTypeKind.USER.name()).orElseThrow();
 
         LinkedAccount account = entityFactory.newEntity(LinkedAccount.class);
         account.setConnObjectKeyValue("admin");
@@ -264,13 +264,12 @@ public class DefaultMappingManagerTest extends 
AbstractTest {
 
         entityManager.flush();
 
-        // 2. verify that dynamic membership is in place
+        // 2. verify that dynamic membership is effective
         assertTrue(userDAO.findAllGroupKeys(user).contains(group.getKey()));
 
         // 3. check propagation attrs
         ExternalResource csv = 
resourceDAO.findById("resource-csv").orElseThrow();
-        Provision provision = 
csv.getProvisionByAnyType(AnyTypeKind.USER.name()).get();
-        assertNotNull(provision);
+        Provision provision = 
csv.getProvisionByAnyType(AnyTypeKind.USER.name()).orElseThrow();
 
         MappingManager.PreparedAttrs attrs = 
mappingManager.prepareAttrsFromAny(
                 user,
diff --git 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
index 02d8256d99..e7c8306a39 100644
--- 
a/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
+++ 
b/fit/core-reference/src/test/java/org/apache/syncope/fit/core/MembershipITCase.java
@@ -342,4 +342,31 @@ public class MembershipITCase extends AbstractITCase {
             assertEquals(ClientExceptionType.InvalidMembership, e.getType());
         }
     }
+
+    @Test
+    public void issueSYNCOPE1944() {
+        TypeExtensionTO typeExt = new TypeExtensionTO();
+        typeExt.setAnyType(AnyTypeKind.USER.name());
+        typeExt.getAuxClasses().add("minimal user");
+
+        GroupCR gcr = GroupITCase.getBasicSample("syncope1944");
+        gcr.getTypeExtensions().add(typeExt);
+
+        GroupTO group = createGroup(gcr).getEntity();
+        assertNotNull(group.getKey());
+
+        UserCR ucr = 
UserITCase.getUniqueSample("[email protected]");
+        ucr.getMemberships().add(new MembershipTO.Builder(group.getKey()).
+                plainAttr(attr("fullname", ucr.getUsername())).
+                plainAttr(attr("userId", ucr.getUsername())).
+                plainAttr(attr("firstname", "Galileo")).
+                plainAttr(attr("surname", "Galilei")).build());
+
+        UserTO user = createUser(ucr).getEntity();
+        assertNotNull(user.getKey());
+
+        assertEquals(
+                "Galilei, Galileo",
+                
user.getMembership(group.getKey()).orElseThrow().getDerAttr("cn").orElseThrow().getValues().getFirst());
+    }
 }

Reply via email to