Repository: cassandra
Updated Branches:
  refs/heads/trunk d62b2cf7c -> 93b64f7b3


"class declared as inner class" error when using UDF

patch by Robert Stupp; reviewed by Tyler Hobbs for CASSANDRA-11391


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/93b64f7b
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/93b64f7b
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/93b64f7b

Branch: refs/heads/trunk
Commit: 93b64f7b355a64d752e7f73d8ad4127004616c70
Parents: d62b2cf
Author: Robert Stupp <sn...@snazy.de>
Authored: Sat Apr 30 18:30:13 2016 +0200
Committer: Robert Stupp <sn...@snazy.de>
Committed: Sat Apr 30 18:30:13 2016 +0200

----------------------------------------------------------------------
 .../cql3/functions/JavaBasedUDFunction.java     |  2 +-
 .../cql3/functions/UDFByteCodeVerifier.java     |  6 +-
 .../cql3/validation/entities/UFTest.java        | 13 ++++
 .../validation/entities/UFVerifierTest.java     | 75 +++++++++++++++-----
 .../entities/udfverify/ClassWithInnerClass.java | 47 ++++++++++++
 .../udfverify/ClassWithInnerClass2.java         | 49 +++++++++++++
 .../udfverify/ClassWithStaticInnerClass.java    | 47 ++++++++++++
 .../entities/udfverify/UsingMapEntry.java       | 50 +++++++++++++
 8 files changed, 270 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java 
b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
index 15103be..ccfc7cf 100644
--- a/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
+++ b/src/java/org/apache/cassandra/cql3/functions/JavaBasedUDFunction.java
@@ -294,7 +294,7 @@ public final class JavaBasedUDFunction extends UDFunction
             }
 
             // Verify the UDF bytecode against use of probably dangerous code
-            Set<String> errors = 
udfByteCodeVerifier.verify(targetClassLoader.classData(targetClassName));
+            Set<String> errors = udfByteCodeVerifier.verify(targetClassName, 
targetClassLoader.classData(targetClassName));
             String validDeclare = "not allowed method declared: " + 
executeInternalName + '(';
             for (Iterator<String> i = errors.iterator(); i.hasNext();)
             {

http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java
----------------------------------------------------------------------
diff --git 
a/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java 
b/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java
index 4bab883..cfaa70f 100644
--- a/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java
+++ b/src/java/org/apache/cassandra/cql3/functions/UDFByteCodeVerifier.java
@@ -80,8 +80,9 @@ public final class UDFByteCodeVerifier
         return this;
     }
 
-    public Set<String> verify(byte[] bytes)
+    public Set<String> verify(String clsName, byte[] bytes)
     {
+        String clsNameSl = clsName.replace('.', '/');
         Set<String> errors = new TreeSet<>(); // it's a TreeSet for unit tests
         ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM5)
         {
@@ -134,7 +135,8 @@ public final class UDFByteCodeVerifier
 
             public void visitInnerClass(String name, String outerName, String 
innerName, int access)
             {
-                errors.add("class declared as inner class");
+                if (clsNameSl.equals(outerName)) // outerName might be null, 
which is true for anonymous inner classes
+                    errors.add("class declared as inner class");
                 super.visitInnerClass(name, outerName, innerName, access);
             }
         };

http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java 
b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
index 1f1ed92..3cd5be7 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/entities/UFTest.java
@@ -2624,6 +2624,19 @@ public class UFTest extends CQLTester
 
         assertRows(execute("SELECT " + f + "(udt) FROM %s"),
                    row(tuple("baz", 88)));
+
+        createFunction(KEYSPACE, "map",
+                       "CREATE FUNCTION %s(my_map map<text, text>)\n" +
+                       "         CALLED ON NULL INPUT\n" +
+                       "         RETURNS text\n" +
+                       "         LANGUAGE java\n" +
+                       "         AS $$\n" +
+                       "             String buffer = \"\";\n" +
+                       "             for(java.util.Map.Entry<String, String> 
entry: my_map.entrySet()) {\n" +
+                       "                 buffer = buffer + entry.getKey() + 
\": \" + entry.getValue() + \", \";\n" +
+                       "             }\n" +
+                       "             return buffer;\n" +
+                       "         $$;\n");
     }
 
     @Test

http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java 
b/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java
index 0b78bf2..9a8e682 100644
--- 
a/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/entities/UFVerifierTest.java
@@ -25,6 +25,7 @@ import java.net.URL;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
+import java.util.Set;
 
 import org.junit.Test;
 
@@ -38,7 +39,10 @@ import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithField;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInitializer;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInitializer2;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInitializer3;
+import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInnerClass;
+import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithInnerClass2;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithStaticInitializer;
+import 
org.apache.cassandra.cql3.validation.entities.udfverify.ClassWithStaticInnerClass;
 import org.apache.cassandra.cql3.validation.entities.udfverify.GoodClass;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronized;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithNotify;
@@ -46,6 +50,7 @@ import 
org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronized
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithWait;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithWaitL;
 import 
org.apache.cassandra.cql3.validation.entities.udfverify.UseOfSynchronizedWithWaitLI;
+import org.apache.cassandra.cql3.validation.entities.udfverify.UsingMapEntry;
 
 import static org.junit.Assert.assertEquals;
 
@@ -57,14 +62,14 @@ public class UFVerifierTest extends CQLTester
     @Test
     public void testByteCodeVerifier()
     {
-        new UDFByteCodeVerifier().verify(readClass(GoodClass.class));
+        verify(GoodClass.class);
     }
 
     @Test
     public void testClassWithField()
     {
         assertEquals(new HashSet<>(Collections.singletonList("field declared: 
field")),
-                     new 
UDFByteCodeVerifier().verify(readClass(ClassWithField.class)));
+                     verify(ClassWithField.class));
     }
 
     @Test
@@ -72,7 +77,7 @@ public class UFVerifierTest extends CQLTester
     {
         assertEquals(new HashSet<>(Arrays.asList("field declared: field",
                                                  "initializer declared")),
-                     new 
UDFByteCodeVerifier().verify(readClass(ClassWithInitializer.class)));
+                     verify(ClassWithInitializer.class));
     }
 
     @Test
@@ -80,91 +85,129 @@ public class UFVerifierTest extends CQLTester
     {
         assertEquals(new HashSet<>(Arrays.asList("field declared: field",
                                                  "initializer declared")),
-                     new 
UDFByteCodeVerifier().verify(readClass(ClassWithInitializer2.class)));
+                     verify(ClassWithInitializer2.class));
     }
 
     @Test
     public void testClassWithInitializer3()
     {
         assertEquals(new HashSet<>(Collections.singletonList("initializer 
declared")),
-                     new 
UDFByteCodeVerifier().verify(readClass(ClassWithInitializer3.class)));
+                     verify(ClassWithInitializer3.class));
     }
 
     @Test
     public void testClassWithStaticInitializer()
     {
         assertEquals(new HashSet<>(Collections.singletonList("static 
initializer declared")),
-                     new 
UDFByteCodeVerifier().verify(readClass(ClassWithStaticInitializer.class)));
+                     verify(ClassWithStaticInitializer.class));
     }
 
     @Test
     public void testUseOfSynchronized()
     {
         assertEquals(new HashSet<>(Collections.singletonList("use of 
synchronized")),
-                     new 
UDFByteCodeVerifier().verify(readClass(UseOfSynchronized.class)));
+                     verify(UseOfSynchronized.class));
     }
 
     @Test
     public void testUseOfSynchronizedWithNotify()
     {
         assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call 
to java.lang.Object.notify()")),
-                     new 
UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithNotify.class)));
+                     verify(UseOfSynchronizedWithNotify.class));
     }
 
     @Test
     public void testUseOfSynchronizedWithNotifyAll()
     {
         assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call 
to java.lang.Object.notifyAll()")),
-                     new 
UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithNotifyAll.class)));
+                     verify(UseOfSynchronizedWithNotifyAll.class));
     }
 
     @Test
     public void testUseOfSynchronizedWithWait()
     {
         assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call 
to java.lang.Object.wait()")),
-                     new 
UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithWait.class)));
+                     verify(UseOfSynchronizedWithWait.class));
     }
 
     @Test
     public void testUseOfSynchronizedWithWaitL()
     {
         assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call 
to java.lang.Object.wait()")),
-                     new 
UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithWaitL.class)));
+                     verify(UseOfSynchronizedWithWaitL.class));
     }
 
     @Test
     public void testUseOfSynchronizedWithWaitI()
     {
         assertEquals(new HashSet<>(Arrays.asList("use of synchronized", "call 
to java.lang.Object.wait()")),
-                     new 
UDFByteCodeVerifier().verify(readClass(UseOfSynchronizedWithWaitLI.class)));
+                     verify(UseOfSynchronizedWithWaitLI.class));
     }
 
     @Test
     public void testCallClone()
     {
         assertEquals(new HashSet<>(Collections.singletonList("call to 
java.lang.Object.clone()")),
-                     new 
UDFByteCodeVerifier().verify(readClass(CallClone.class)));
+                     verify(CallClone.class));
     }
 
     @Test
     public void testCallFinalize()
     {
         assertEquals(new HashSet<>(Collections.singletonList("call to 
java.lang.Object.finalize()")),
-                     new 
UDFByteCodeVerifier().verify(readClass(CallFinalize.class)));
+                     verify(CallFinalize.class));
     }
 
     @Test
     public void testCallComDatastax()
     {
         assertEquals(new HashSet<>(Collections.singletonList("call to 
com.datastax.driver.core.DataType.cint()")),
-                     new 
UDFByteCodeVerifier().addDisallowedPackage("com/").verify(readClass(CallComDatastax.class)));
+                     verify("com/", CallComDatastax.class));
     }
 
     @Test
     public void testCallOrgApache()
     {
         assertEquals(new HashSet<>(Collections.singletonList("call to 
org.apache.cassandra.config.DatabaseDescriptor.getClusterName()")),
-                     new 
UDFByteCodeVerifier().addDisallowedPackage("org/").verify(readClass(CallOrgApache.class)));
+                     verify("org/", CallOrgApache.class));
+    }
+
+    @Test
+    public void testClassStaticInnerClass()
+    {
+        assertEquals(new HashSet<>(Collections.singletonList("class declared 
as inner class")),
+                     verify(ClassWithStaticInnerClass.class));
+    }
+
+    @Test
+    public void testUsingMapEntry()
+    {
+        assertEquals(Collections.emptySet(),
+                     verify(UsingMapEntry.class));
+    }
+
+    @Test
+    public void testClassInnerClass()
+    {
+        assertEquals(new HashSet<>(Collections.singletonList("class declared 
as inner class")),
+                     verify(ClassWithInnerClass.class));
+    }
+
+    @Test
+    public void testClassInnerClass2()
+    {
+        assertEquals(Collections.emptySet(),
+                     verify(ClassWithInnerClass2.class));
+    }
+
+    private Set<String> verify(Class cls)
+    {
+        return new UDFByteCodeVerifier().verify(cls.getName(), readClass(cls));
+    }
+
+    private Set<String> verify(String disallowedPkg, Class cls)
+    {
+        return new 
UDFByteCodeVerifier().addDisallowedPackage(disallowedPkg).verify(cls.getName(), 
readClass(cls));
     }
 
     @SuppressWarnings("resource")

http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java
 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java
new file mode 100644
index 0000000..2166771
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.validation.entities.udfverify;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import com.datastax.driver.core.TypeCodec;
+import org.apache.cassandra.cql3.functions.JavaUDF;
+import org.apache.cassandra.cql3.functions.UDFContext;
+
+/**
+ * Used by {@link 
org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
+ */
+public final class ClassWithInnerClass extends JavaUDF
+{
+    public ClassWithInnerClass(TypeCodec<Object> returnDataType, 
TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
+    {
+        super(returnDataType, argDataTypes, udfContext);
+    }
+
+    protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> 
params)
+    {
+        return null;
+    }
+
+    // this is NOT fine
+    final class ClassWithInner_Inner {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java
 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java
new file mode 100644
index 0000000..9c18510
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithInnerClass2.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.validation.entities.udfverify;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import com.datastax.driver.core.TypeCodec;
+import org.apache.cassandra.cql3.functions.JavaUDF;
+import org.apache.cassandra.cql3.functions.UDFContext;
+
+/**
+ * Used by {@link 
org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
+ */
+public final class ClassWithInnerClass2 extends JavaUDF
+{
+    public ClassWithInnerClass2(TypeCodec<Object> returnDataType, 
TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
+    {
+        super(returnDataType, argDataTypes, udfContext);
+    }
+
+    protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> 
params)
+    {
+        // this is fine
+        new Runnable() {
+            public void run()
+            {
+
+            }
+        }.run();
+        return null;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java
 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java
new file mode 100644
index 0000000..fada145
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/ClassWithStaticInnerClass.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.validation.entities.udfverify;
+
+import java.nio.ByteBuffer;
+import java.util.List;
+
+import com.datastax.driver.core.TypeCodec;
+import org.apache.cassandra.cql3.functions.JavaUDF;
+import org.apache.cassandra.cql3.functions.UDFContext;
+
+/**
+ * Used by {@link 
org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
+ */
+public final class ClassWithStaticInnerClass extends JavaUDF
+{
+    public ClassWithStaticInnerClass(TypeCodec<Object> returnDataType, 
TypeCodec<Object>[] argDataTypes, UDFContext udfContext)
+    {
+        super(returnDataType, argDataTypes, udfContext);
+    }
+
+    protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> 
params)
+    {
+        return null;
+    }
+
+    // this is NOT fine
+    static final class ClassWithStaticInner_Inner {
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/cassandra/blob/93b64f7b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java
----------------------------------------------------------------------
diff --git 
a/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java
 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java
new file mode 100644
index 0000000..5091dc1
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/entities/udfverify/UsingMapEntry.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.cql3.validation.entities.udfverify;
+
+import java.nio.ByteBuffer;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.datastax.driver.core.TypeCodec;
+import org.apache.cassandra.cql3.functions.JavaUDF;
+import org.apache.cassandra.cql3.functions.UDFContext;
+
+/**
+ * Used by {@link 
org.apache.cassandra.cql3.validation.entities.UFVerifierTest}.
+ */
+public final class UsingMapEntry extends JavaUDF
+{
+    public UsingMapEntry(TypeCodec<Object> returnDataType, TypeCodec<Object>[] 
argDataTypes, UDFContext udfContext)
+    {
+        super(returnDataType, argDataTypes, udfContext);
+    }
+
+    protected ByteBuffer executeImpl(int protocolVersion, List<ByteBuffer> 
params)
+    {
+        Map<String, String> map = new HashMap<>();
+        // Map.Entry is passed in as an "inner class usage"
+        for (Map.Entry<String, String> stringStringEntry : map.entrySet())
+        {
+
+        }
+        return null;
+    }
+}

Reply via email to