From 65bfde552a968d358c269484a1b8a1af5b65c228 Mon Sep 17 00:00:00 2001 From: Haohui Mai Date: Tue, 3 Mar 2015 17:54:13 -0800 Subject: [PATCH] HDFS-6565. Use jackson instead jetty json in hdfs-client. Contributed by Akira AJISAKA. --- hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt | 3 + .../org/apache/hadoop/hdfs/web/JsonUtil.java | 224 ++++++++---------- .../hadoop/hdfs/web/WebHdfsFileSystem.java | 22 +- .../apache/hadoop/hdfs/web/TestJsonUtil.java | 22 +- 4 files changed, 131 insertions(+), 140 deletions(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index df5520e9015..69a410fe538 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -771,6 +771,9 @@ Release 2.7.0 - UNRELEASED HDFS-7757. Misleading error messages in FSImage.java. (Brahma Reddy Battula via Arpit Agarwal) + HDFS-6565. Use jackson instead jetty json in hdfs-client. + (Akira Ajisaka via wheat9) + BREAKDOWN OF HDFS-7584 SUBTASKS AND RELATED JIRAS HDFS-7720. Quota by Storage Type API, tools and ClientNameNode diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java index 69ef9269b18..edaa4a27dc7 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/JsonUtil.java @@ -21,7 +21,6 @@ import org.apache.hadoop.fs.*; import org.apache.hadoop.fs.permission.AclEntry; import org.apache.hadoop.fs.permission.AclStatus; import org.apache.hadoop.fs.permission.FsPermission; -import org.apache.hadoop.hdfs.protocol.BlockStoragePolicy; import org.apache.hadoop.hdfs.DFSUtil; import org.apache.hadoop.hdfs.XAttrHelper; import org.apache.hadoop.hdfs.protocol.*; @@ -35,7 +34,8 @@ import org.apache.hadoop.security.token.Token; import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.util.DataChecksum; import org.apache.hadoop.util.StringUtils; -import org.mortbay.util.ajax.JSON; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.ObjectReader; import com.google.common.collect.Lists; import com.google.common.collect.Maps; @@ -95,59 +95,6 @@ public class JsonUtil { return (Token)toToken(m); } - /** Convert a Token[] to a JSON array. */ - private static Object[] toJsonArray(final Token[] array - ) throws IOException { - if (array == null) { - return null; - } else if (array.length == 0) { - return EMPTY_OBJECT_ARRAY; - } else { - final Object[] a = new Object[array.length]; - for(int i = 0; i < array.length; i++) { - a[i] = toJsonMap(array[i]); - } - return a; - } - } - - /** Convert a token object to a JSON string. */ - public static String toJsonString(final Token[] tokens - ) throws IOException { - if (tokens == null) { - return null; - } - - final Map m = new TreeMap(); - m.put(Token.class.getSimpleName(), toJsonArray(tokens)); - return toJsonString(Token.class.getSimpleName() + "s", m); - } - - /** Convert an Object[] to a List>. */ - private static List> toTokenList(final Object[] objects) throws IOException { - if (objects == null) { - return null; - } else if (objects.length == 0) { - return Collections.emptyList(); - } else { - final List> list = new ArrayList>(objects.length); - for(int i = 0; i < objects.length; i++) { - list.add(toToken((Map)objects[i])); - } - return list; - } - } - - /** Convert a JSON map to a List>. */ - public static List> toTokenList(final Map json) throws IOException { - if (json == null) { - return null; - } - - final Map m = (Map)json.get(Token.class.getSimpleName() + "s"); - return toTokenList((Object[])m.get(Token.class.getSimpleName())); - } - /** Convert an exception object to a Json string. */ public static String toJsonString(final Exception e) { final Map m = new TreeMap(); @@ -173,7 +120,12 @@ public class JsonUtil { public static String toJsonString(final String key, final Object value) { final Map m = new TreeMap(); m.put(key, value); - return JSON.toString(m); + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.writeValueAsString(m); + } catch (IOException ignored) { + } + return null; } /** Convert a FsPermission object to a string. */ @@ -233,7 +185,13 @@ public class JsonUtil { m.put("fileId", status.getFileId()); m.put("childrenNum", status.getChildrenNum()); m.put("storagePolicy", status.getStoragePolicy()); - return includeType ? toJsonString(FileStatus.class, m): JSON.toString(m); + ObjectMapper mapper = new ObjectMapper(); + try { + return includeType ? + toJsonString(FileStatus.class, m) : mapper.writeValueAsString(m); + } catch (IOException ignored) { + } + return null; } /** Convert a Json map to a HdfsFileStatus object. */ @@ -249,23 +207,21 @@ public class JsonUtil { final byte[] symlink = type != PathType.SYMLINK? null : DFSUtil.string2Bytes((String)m.get("symlink")); - final long len = (Long) m.get("length"); + final long len = ((Number) m.get("length")).longValue(); final String owner = (String) m.get("owner"); final String group = (String) m.get("group"); final FsPermission permission = toFsPermission((String) m.get("permission"), (Boolean)m.get("aclBit"), (Boolean)m.get("encBit")); - final long aTime = (Long) m.get("accessTime"); - final long mTime = (Long) m.get("modificationTime"); - final long blockSize = (Long) m.get("blockSize"); - final short replication = (short) (long) (Long) m.get("replication"); - final long fileId = m.containsKey("fileId") ? (Long) m.get("fileId") - : INodeId.GRANDFATHER_INODE_ID; - Long childrenNumLong = (Long) m.get("childrenNum"); - final int childrenNum = (childrenNumLong == null) ? -1 - : childrenNumLong.intValue(); + final long aTime = ((Number) m.get("accessTime")).longValue(); + final long mTime = ((Number) m.get("modificationTime")).longValue(); + final long blockSize = ((Number) m.get("blockSize")).longValue(); + final short replication = ((Number) m.get("replication")).shortValue(); + final long fileId = m.containsKey("fileId") ? + ((Number) m.get("fileId")).longValue() : INodeId.GRANDFATHER_INODE_ID; + final int childrenNum = getInt(m, "childrenNum", -1); final byte storagePolicy = m.containsKey("storagePolicy") ? - (byte) (long) (Long) m.get("storagePolicy") : - BlockStoragePolicySuite.ID_UNSPECIFIED; + (byte) ((Number) m.get("storagePolicy")).longValue() : + BlockStoragePolicySuite.ID_UNSPECIFIED; return new HdfsFileStatus(len, type == PathType.DIRECTORY, replication, blockSize, mTime, aTime, permission, owner, group, symlink, DFSUtil.string2Bytes(localName), fileId, childrenNum, null, storagePolicy); @@ -292,9 +248,10 @@ public class JsonUtil { } final String blockPoolId = (String)m.get("blockPoolId"); - final long blockId = (Long)m.get("blockId"); - final long numBytes = (Long)m.get("numBytes"); - final long generationStamp = (Long)m.get("generationStamp"); + final long blockId = ((Number) m.get("blockId")).longValue(); + final long numBytes = ((Number) m.get("numBytes")).longValue(); + final long generationStamp = + ((Number) m.get("generationStamp")).longValue(); return new ExtendedBlock(blockPoolId, blockId, numBytes, generationStamp); } @@ -335,7 +292,7 @@ public class JsonUtil { if (value == null) { return defaultValue; } - return (int) (long) (Long) value; + return ((Number) value).intValue(); } private static long getLong(Map m, String key, final long defaultValue) { @@ -343,7 +300,7 @@ public class JsonUtil { if (value == null) { return defaultValue; } - return (Long) value; + return ((Number) value).longValue(); } private static String getString(Map m, String key, @@ -355,6 +312,15 @@ public class JsonUtil { return (String) value; } + static List getList(Map m, String key) { + Object list = m.get(key); + if (list instanceof List) { + return (List) list; + } else { + return null; + } + } + /** Convert a Json map to an DatanodeInfo object. */ static DatanodeInfo toDatanodeInfo(final Map m) throws IOException { @@ -402,9 +368,9 @@ public class JsonUtil { (String)m.get("hostName"), (String)m.get("storageID"), xferPort, - (int)(long)(Long)m.get("infoPort"), + ((Number) m.get("infoPort")).intValue(), getInt(m, "infoSecurePort", 0), - (int)(long)(Long)m.get("ipcPort"), + ((Number) m.get("ipcPort")).intValue(), getLong(m, "capacity", 0l), getLong(m, "dfsUsed", 0l), @@ -434,16 +400,17 @@ public class JsonUtil { } /** Convert an Object[] to a DatanodeInfo[]. */ - private static DatanodeInfo[] toDatanodeInfoArray(final Object[] objects) + private static DatanodeInfo[] toDatanodeInfoArray(final List objects) throws IOException { if (objects == null) { return null; - } else if (objects.length == 0) { + } else if (objects.isEmpty()) { return EMPTY_DATANODE_INFO_ARRAY; } else { - final DatanodeInfo[] array = new DatanodeInfo[objects.length]; - for(int i = 0; i < array.length; i++) { - array[i] = toDatanodeInfo((Map) objects[i]); + final DatanodeInfo[] array = new DatanodeInfo[objects.size()]; + int i = 0; + for (Object object : objects) { + array[i++] = toDatanodeInfo((Map) object); } return array; } @@ -474,11 +441,11 @@ public class JsonUtil { final ExtendedBlock b = toExtendedBlock((Map)m.get("block")); final DatanodeInfo[] locations = toDatanodeInfoArray( - (Object[])m.get("locations")); - final long startOffset = (Long)m.get("startOffset"); + getList(m, "locations")); + final long startOffset = ((Number) m.get("startOffset")).longValue(); final boolean isCorrupt = (Boolean)m.get("isCorrupt"); final DatanodeInfo[] cachedLocations = toDatanodeInfoArray( - (Object[])m.get("cachedLocations")); + getList(m, "cachedLocations")); final LocatedBlock locatedblock = new LocatedBlock(b, locations, null, null, startOffset, isCorrupt, cachedLocations); @@ -502,17 +469,17 @@ public class JsonUtil { } } - /** Convert an Object[] to a List of LocatedBlock. */ - private static List toLocatedBlockList(final Object[] objects - ) throws IOException { + /** Convert an List of Object to a List of LocatedBlock. */ + private static List toLocatedBlockList( + final List objects) throws IOException { if (objects == null) { return null; - } else if (objects.length == 0) { + } else if (objects.isEmpty()) { return Collections.emptyList(); } else { - final List list = new ArrayList(objects.length); - for(int i = 0; i < objects.length; i++) { - list.add(toLocatedBlock((Map)objects[i])); + final List list = new ArrayList<>(objects.size()); + for (Object object : objects) { + list.add(toLocatedBlock((Map) object)); } return list; } @@ -543,10 +510,10 @@ public class JsonUtil { } final Map m = (Map)json.get(LocatedBlocks.class.getSimpleName()); - final long fileLength = (Long)m.get("fileLength"); + final long fileLength = ((Number) m.get("fileLength")).longValue(); final boolean isUnderConstruction = (Boolean)m.get("isUnderConstruction"); final List locatedBlocks = toLocatedBlockList( - (Object[])m.get("locatedBlocks")); + getList(m, "locatedBlocks")); final LocatedBlock lastLocatedBlock = toLocatedBlock( (Map)m.get("lastLocatedBlock")); final boolean isLastBlockComplete = (Boolean)m.get("isLastBlockComplete"); @@ -577,12 +544,12 @@ public class JsonUtil { } final Map m = (Map)json.get(ContentSummary.class.getSimpleName()); - final long length = (Long)m.get("length"); - final long fileCount = (Long)m.get("fileCount"); - final long directoryCount = (Long)m.get("directoryCount"); - final long quota = (Long)m.get("quota"); - final long spaceConsumed = (Long)m.get("spaceConsumed"); - final long spaceQuota = (Long)m.get("spaceQuota"); + final long length = ((Number) m.get("length")).longValue(); + final long fileCount = ((Number) m.get("fileCount")).longValue(); + final long directoryCount = ((Number) m.get("directoryCount")).longValue(); + final long quota = ((Number) m.get("quota")).longValue(); + final long spaceConsumed = ((Number) m.get("spaceConsumed")).longValue(); + final long spaceQuota = ((Number) m.get("spaceQuota")).longValue(); return new ContentSummary(length, fileCount, directoryCount, quota, spaceConsumed, spaceQuota); @@ -610,7 +577,7 @@ public class JsonUtil { final Map m = (Map)json.get(FileChecksum.class.getSimpleName()); final String algorithm = (String)m.get("algorithm"); - final int length = (int)(long)(Long)m.get("length"); + final int length = ((Number) m.get("length")).intValue(); final byte[] bytes = StringUtils.hexStringToByte((String)m.get("bytes")); final DataInputStream in = new DataInputStream(new ByteArrayInputStream(bytes)); @@ -654,7 +621,13 @@ public class JsonUtil { m.put("owner", status.getOwner()); m.put("group", status.getGroup()); m.put("stickyBit", status.isStickyBit()); - m.put("entries", status.getEntries()); + + final List stringEntries = new ArrayList<>(); + for (AclEntry entry : status.getEntries()) { + stringEntries.add(entry.toString()); + } + m.put("entries", stringEntries); + FsPermission perm = status.getPermission(); if (perm != null) { m.put("permission", toString(perm)); @@ -668,7 +641,13 @@ public class JsonUtil { final Map> finalMap = new TreeMap>(); finalMap.put(AclStatus.class.getSimpleName(), m); - return JSON.toString(finalMap); + + ObjectMapper mapper = new ObjectMapper(); + try { + return mapper.writeValueAsString(finalMap); + } catch (IOException ignored) { + } + return null; } /** Convert a Json map to a AclStatus object. */ @@ -689,11 +668,11 @@ public class JsonUtil { (Boolean) m.get("aclBit"), (Boolean) m.get("encBit")); aclStatusBuilder.setPermission(permission); } - final Object[] entries = (Object[]) m.get("entries"); + final List entries = (List) m.get("entries"); List aclEntryList = new ArrayList(); - for (int i = 0; i < entries.length; i++) { - AclEntry aclEntry = AclEntry.parseAclEntry((String) entries[i], true); + for (Object entry : entries) { + AclEntry aclEntry = AclEntry.parseAclEntry((String) entry, true); aclEntryList.add(aclEntry); } aclStatusBuilder.addEntries(aclEntryList); @@ -732,7 +711,8 @@ public class JsonUtil { final XAttrCodec encoding) throws IOException { final Map finalMap = new TreeMap(); finalMap.put("XAttrs", toJsonArray(xAttrs, encoding)); - return JSON.toString(finalMap); + ObjectMapper mapper = new ObjectMapper(); + return mapper.writeValueAsString(finalMap); } public static String toJsonString(final List xAttrs) @@ -741,10 +721,11 @@ public class JsonUtil { for (XAttr xAttr : xAttrs) { names.add(XAttrHelper.getPrefixName(xAttr)); } - String ret = JSON.toString(names); + ObjectMapper mapper = new ObjectMapper(); + String ret = mapper.writeValueAsString(names); final Map finalMap = new TreeMap(); finalMap.put("XAttrNames", ret); - return JSON.toString(finalMap); + return mapper.writeValueAsString(finalMap); } public static byte[] getXAttr(final Map json, final String name) @@ -760,14 +741,13 @@ public class JsonUtil { return null; } - + public static Map toXAttrs(final Map json) throws IOException { if (json == null) { return null; } - - return toXAttrMap((Object[])json.get("XAttrs")); + return toXAttrMap(getList(json, "XAttrs")); } public static List toXAttrNames(final Map json) @@ -777,27 +757,27 @@ public class JsonUtil { } final String namesInJson = (String) json.get("XAttrNames"); - final Object[] xattrs = (Object[]) JSON.parse(namesInJson); - final List names = Lists.newArrayListWithCapacity(json.keySet() - .size()); + ObjectReader reader = new ObjectMapper().reader(List.class); + final List xattrs = reader.readValue(namesInJson); + final List names = + Lists.newArrayListWithCapacity(json.keySet().size()); - for (int i = 0; i < xattrs.length; i++) { - names.add((String) (xattrs[i])); + for (Object xattr : xattrs) { + names.add((String) xattr); } return names; } - - - private static Map toXAttrMap(final Object[] objects) + + private static Map toXAttrMap(final List objects) throws IOException { if (objects == null) { return null; - } else if (objects.length == 0) { + } else if (objects.isEmpty()) { return Maps.newHashMap(); } else { final Map xAttrs = Maps.newHashMap(); - for(int i = 0; i < objects.length; i++) { - Map m = (Map) objects[i]; + for (Object object : objects) { + Map m = (Map) object; String name = (String) m.get("name"); String value = (String) m.get("value"); xAttrs.put(name, decodeXAttrValue(value)); diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java index 268deabc525..3ca89f5dee7 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/web/WebHdfsFileSystem.java @@ -22,7 +22,6 @@ import java.io.BufferedOutputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.InetSocketAddress; import java.net.MalformedURLException; @@ -80,10 +79,10 @@ import org.apache.hadoop.security.token.TokenIdentifier; import org.apache.hadoop.security.token.TokenSelector; import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenSelector; import org.apache.hadoop.util.Progressable; -import org.mortbay.util.ajax.JSON; +import org.apache.hadoop.util.StringUtils; +import org.codehaus.jackson.map.ObjectMapper; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; @@ -323,7 +322,8 @@ public class WebHdfsFileSystem extends FileSystem + "\" (parsed=\"" + parsed + "\")"); } } - return (Map)JSON.parse(new InputStreamReader(in, Charsets.UTF_8)); + ObjectMapper mapper = new ObjectMapper(); + return mapper.reader(Map.class).readValue(in); } finally { in.close(); } @@ -1291,13 +1291,15 @@ public class WebHdfsFileSystem extends FileSystem @Override FileStatus[] decodeResponse(Map json) { final Map rootmap = (Map)json.get(FileStatus.class.getSimpleName() + "es"); - final Object[] array = (Object[])rootmap.get(FileStatus.class.getSimpleName()); + final List array = JsonUtil.getList( + rootmap, FileStatus.class.getSimpleName()); //convert FileStatus - final FileStatus[] statuses = new FileStatus[array.length]; - for (int i = 0; i < array.length; i++) { - final Map m = (Map)array[i]; - statuses[i] = makeQualified(JsonUtil.toFileStatus(m, false), f); + final FileStatus[] statuses = new FileStatus[array.size()]; + int i = 0; + for (Object object : array) { + final Map m = (Map) object; + statuses[i++] = makeQualified(JsonUtil.toFileStatus(m, false), f); } return statuses; } @@ -1348,7 +1350,7 @@ public class WebHdfsFileSystem extends FileSystem new TokenArgumentParam(token.encodeToUrlString())) { @Override Long decodeResponse(Map json) throws IOException { - return (Long) json.get("long"); + return ((Number) json.get("long")).longValue(); } }.run(); } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java index 3eba7db9c2c..0ed38f2610f 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/web/TestJsonUtil.java @@ -42,9 +42,10 @@ import org.apache.hadoop.hdfs.protocol.DatanodeInfo; import org.apache.hadoop.hdfs.protocol.HdfsFileStatus; import org.apache.hadoop.hdfs.server.namenode.INodeId; import org.apache.hadoop.util.Time; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.map.ObjectReader; import org.junit.Assert; import org.junit.Test; -import org.mortbay.util.ajax.JSON; import com.google.common.collect.Lists; @@ -58,7 +59,7 @@ public class TestJsonUtil { } @Test - public void testHdfsFileStatus() { + public void testHdfsFileStatus() throws IOException { final long now = Time.now(); final String parent = "/dir"; final HdfsFileStatus status = new HdfsFileStatus(1001L, false, 3, 1L << 26, @@ -70,7 +71,9 @@ public class TestJsonUtil { System.out.println("fstatus = " + fstatus); final String json = JsonUtil.toJsonString(status, true); System.out.println("json = " + json.replace(",", ",\n ")); - final HdfsFileStatus s2 = JsonUtil.toFileStatus((Map)JSON.parse(json), true); + ObjectReader reader = new ObjectMapper().reader(Map.class); + final HdfsFileStatus s2 = + JsonUtil.toFileStatus((Map) reader.readValue(json), true); final FileStatus fs2 = toFileStatus(s2, parent); System.out.println("s2 = " + s2); System.out.println("fs2 = " + fs2); @@ -153,10 +156,11 @@ public class TestJsonUtil { } @Test - public void testToAclStatus() { + public void testToAclStatus() throws IOException { String jsonString = "{\"AclStatus\":{\"entries\":[\"user::rwx\",\"user:user1:rw-\",\"group::rw-\",\"other::r-x\"],\"group\":\"supergroup\",\"owner\":\"testuser\",\"stickyBit\":false}}"; - Map json = (Map) JSON.parse(jsonString); + ObjectReader reader = new ObjectMapper().reader(Map.class); + Map json = reader.readValue(jsonString); List aclSpec = Lists.newArrayList(aclEntry(ACCESS, USER, ALL), @@ -215,7 +219,8 @@ public class TestJsonUtil { String jsonString = "{\"XAttrs\":[{\"name\":\"user.a1\",\"value\":\"0x313233\"}," + "{\"name\":\"user.a2\",\"value\":\"0x313131\"}]}"; - Map json = (Map)JSON.parse(jsonString); + ObjectReader reader = new ObjectMapper().reader(Map.class); + Map json = reader.readValue(jsonString); XAttr xAttr1 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). setName("a1").setValue(XAttrCodec.decodeValue("0x313233")).build(); XAttr xAttr2 = (new XAttr.Builder()).setNameSpace(XAttr.NameSpace.USER). @@ -240,8 +245,9 @@ public class TestJsonUtil { String jsonString = "{\"XAttrs\":[{\"name\":\"user.a1\",\"value\":\"0x313233\"}," + "{\"name\":\"user.a2\",\"value\":\"0x313131\"}]}"; - Map json = (Map) JSON.parse(jsonString); - + ObjectReader reader = new ObjectMapper().reader(Map.class); + Map json = reader.readValue(jsonString); + // Get xattr: user.a2 byte[] value = JsonUtil.getXAttr(json, "user.a2"); Assert.assertArrayEquals(XAttrCodec.decodeValue("0x313131"), value);