Skip to content

Commit 08c5c6b

Browse files
virajjasaniApache9
authored andcommitted
HBASE-23015 : Moving from Jackson2 to shaded Gson (#616)
* Backport HBASE-20587 * moving to shaded gson with jdk7 compatibility * Include jackson-mapper-asl for testing-util because of Hadoop * Update shaded jar check to allow hbase-thirdparty libs Signed-off-by: Sean Busbey <busbey@apache.org> Co-authored-by: Duo Zhang <zhangduo@apache.org>
1 parent 62f267a commit 08c5c6b

File tree

22 files changed

+296
-188
lines changed

22 files changed

+296
-188
lines changed

hbase-client/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@
252252
<artifactId>junit</artifactId>
253253
<scope>test</scope>
254254
</dependency>
255+
<dependency>
256+
<groupId>org.apache.hbase.thirdparty</groupId>
257+
<artifactId>hbase-shaded-gson</artifactId>
258+
</dependency>
255259
</dependencies>
256260

257261
<profiles>

hbase-client/src/main/java/org/apache/hadoop/hbase/util/JsonMapper.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
*/
1919
package org.apache.hadoop.hbase.util;
2020

21-
import com.fasterxml.jackson.databind.ObjectMapper;
2221
import java.io.IOException;
2322
import java.util.Map;
2423

2524
import org.apache.hadoop.hbase.classification.InterfaceAudience;
2625
import org.apache.hadoop.hbase.classification.InterfaceStability;
26+
import org.apache.hbase.thirdparty.com.google.gson.Gson;
2727

2828
/**
2929
* Utility class for converting objects to JSON
@@ -34,12 +34,13 @@ public final class JsonMapper {
3434
private JsonMapper() {
3535
}
3636

37-
private static final ObjectMapper MAPPER = new ObjectMapper();
37+
private static final Gson GSON = GsonUtil.createGson().create();
3838

39-
public static String writeMapAsString(Map<String, Object> map) throws IOException {
39+
public static String writeMapAsString(Map<String, Object> map) throws IOException {
4040
return writeObjectAsString(map);
4141
}
42-
public static String writeObjectAsString(Object object) throws IOException {
43-
return MAPPER.writeValueAsString(object);
42+
43+
public static String writeObjectAsString(Object object) throws IOException {
44+
return GSON.toJson(object);
4445
}
4546
}

hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestOperation.java

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,10 @@
2727
import org.junit.Assert;
2828
import org.junit.Test;
2929

30-
import com.fasterxml.jackson.databind.ObjectMapper;
3130
import java.io.IOException;
31+
import java.lang.reflect.Type;
3232
import java.nio.ByteBuffer;
3333
import java.util.Arrays;
34-
import java.util.HashMap;
3534
import java.util.List;
3635
import java.util.Map;
3736

@@ -62,9 +61,9 @@
6261
import org.apache.hadoop.hbase.filter.WhileMatchFilter;
6362
import org.apache.hadoop.hbase.util.BuilderStyleTest;
6463
import org.apache.hadoop.hbase.util.Bytes;
65-
66-
import org.junit.Assert;
67-
import org.junit.Test;
64+
import org.apache.hadoop.hbase.util.GsonUtil;
65+
import org.apache.hbase.thirdparty.com.google.gson.Gson;
66+
import org.apache.hbase.thirdparty.com.google.gson.reflect.TypeToken;
6867
import org.junit.experimental.categories.Category;
6968

7069
/**
@@ -78,7 +77,7 @@ public class TestOperation {
7877
private static byte [] QUALIFIER = Bytes.toBytes("testQualifier");
7978
private static byte [] VALUE = Bytes.toBytes("testValue");
8079

81-
private static ObjectMapper mapper = new ObjectMapper();
80+
private static Gson GSON = GsonUtil.createGson().create();
8281

8382
private static List<Long> TS_LIST = Arrays.asList(2L, 3L, 5L);
8483
private static TimestampsFilter TS_FILTER = new TimestampsFilter(TS_LIST);
@@ -304,7 +303,9 @@ public void testOperationJSON() throws IOException {
304303
scan.addColumn(FAMILY, QUALIFIER);
305304
// get its JSON representation, and parse it
306305
String json = scan.toJSON();
307-
Map<String, Object> parsedJSON = mapper.readValue(json, HashMap.class);
306+
Type typeOfHashMap = new TypeToken<Map<String, Object>>() {
307+
}.getType();
308+
Map<String, Object> parsedJSON = GSON.fromJson(json, typeOfHashMap);
308309
// check for the row
309310
assertEquals("startRow incorrect in Scan.toJSON()",
310311
Bytes.toStringBinary(ROW), parsedJSON.get("startRow"));
@@ -322,7 +323,7 @@ public void testOperationJSON() throws IOException {
322323
get.addColumn(FAMILY, QUALIFIER);
323324
// get its JSON representation, and parse it
324325
json = get.toJSON();
325-
parsedJSON = mapper.readValue(json, HashMap.class);
326+
parsedJSON = GSON.fromJson(json, typeOfHashMap);
326327
// check for the row
327328
assertEquals("row incorrect in Get.toJSON()",
328329
Bytes.toStringBinary(ROW), parsedJSON.get("row"));
@@ -340,7 +341,7 @@ public void testOperationJSON() throws IOException {
340341
put.add(FAMILY, QUALIFIER, VALUE);
341342
// get its JSON representation, and parse it
342343
json = put.toJSON();
343-
parsedJSON = mapper.readValue(json, HashMap.class);
344+
parsedJSON = GSON.fromJson(json, typeOfHashMap);
344345
// check for the row
345346
assertEquals("row absent in Put.toJSON()",
346347
Bytes.toStringBinary(ROW), parsedJSON.get("row"));
@@ -354,14 +355,14 @@ public void testOperationJSON() throws IOException {
354355
Bytes.toStringBinary(QUALIFIER),
355356
kvMap.get("qualifier"));
356357
assertEquals("Value length incorrect in Put.toJSON()",
357-
VALUE.length, kvMap.get("vlen"));
358+
VALUE.length, ((Number) kvMap.get("vlen")).intValue());
358359

359360
// produce a Delete operation
360361
Delete delete = new Delete(ROW);
361362
delete.deleteColumn(FAMILY, QUALIFIER);
362363
// get its JSON representation, and parse it
363364
json = delete.toJSON();
364-
parsedJSON = mapper.readValue(json, HashMap.class);
365+
parsedJSON = GSON.fromJson(json, typeOfHashMap);
365366
// check for the row
366367
assertEquals("row absent in Delete.toJSON()",
367368
Bytes.toStringBinary(ROW), parsedJSON.get("row"));

hbase-common/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@
277277
<artifactId>jackson-mapper-asl</artifactId>
278278
<scope>provided</scope>
279279
</dependency>
280+
<dependency>
281+
<groupId>org.apache.hbase.thirdparty</groupId>
282+
<artifactId>hbase-shaded-gson</artifactId>
283+
</dependency>
280284
<dependency>
281285
<groupId>com.fasterxml.jackson.jaxrs</groupId>
282286
<artifactId>jackson-jaxrs-json-provider</artifactId>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/**
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
package org.apache.hadoop.hbase.util;
19+
20+
import java.io.IOException;
21+
22+
import org.apache.hadoop.hbase.classification.InterfaceAudience;
23+
import org.apache.hbase.thirdparty.com.google.gson.GsonBuilder;
24+
import org.apache.hbase.thirdparty.com.google.gson.LongSerializationPolicy;
25+
26+
/**
27+
* Helper class for gson.
28+
*/
29+
@InterfaceAudience.Private
30+
public final class GsonUtil {
31+
32+
private GsonUtil() {
33+
}
34+
35+
/**
36+
* Create a builder which is used to create a Gson instance.
37+
* <p/>
38+
* Will set some common configs for the builder.
39+
*/
40+
public static GsonBuilder createGson() {
41+
return new GsonBuilder().setLongSerializationPolicy(LongSerializationPolicy.STRING);
42+
}
43+
}

hbase-resource-bundle/src/main/resources/supplemental-models.xml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,25 @@ Copyright 2005 Sun Microsystems, Inc. and portions Copyright Apache Software Fou
16651665
</licenses>
16661666
</project>
16671667
</supplement>
1668+
<supplement>
1669+
<project>
1670+
<groupId>com.google.errorprone</groupId>
1671+
<artifactId>error_prone_annotations</artifactId>
1672+
1673+
<organization>
1674+
<name>Google</name>
1675+
<url>http://www.google.com</url>
1676+
</organization>
1677+
<licenses>
1678+
<license>
1679+
<!-- It has been incorrectly called Apache 2.0 in the original pom-->
1680+
<name>Apache License, Version 2.0</name>
1681+
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
1682+
<distribution>repo</distribution>
1683+
</license>
1684+
</licenses>
1685+
</project>
1686+
</supplement>
16681687
<supplement>
16691688
<project>
16701689
<groupId>org.jamon</groupId>

hbase-server/pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,10 @@
484484
<groupId>org.apache.commons</groupId>
485485
<artifactId>commons-math</artifactId>
486486
</dependency>
487+
<dependency>
488+
<groupId>org.apache.hbase.thirdparty</groupId>
489+
<artifactId>hbase-shaded-gson</artifactId>
490+
</dependency>
487491
<dependency>
488492
<groupId>log4j</groupId>
489493
<artifactId>log4j</artifactId>

hbase-server/src/main/java/org/apache/hadoop/hbase/http/jmx/JMXJsonServlet.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -163,14 +163,14 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro
163163
try {
164164
jsonpcb = checkCallbackName(request.getParameter(CALLBACK_PARAM));
165165
writer = response.getWriter();
166-
beanWriter = this.jsonBeanWriter.open(writer);
167166
// "callback" parameter implies JSONP outpout
168167
if (jsonpcb != null) {
169168
response.setContentType("application/javascript; charset=utf8");
170169
writer.write(jsonpcb + "(");
171170
} else {
172171
response.setContentType("application/json; charset=utf8");
173172
}
173+
beanWriter = this.jsonBeanWriter.open(writer);
174174
// Should we output description on each attribute and bean?
175175
String tmpStr = request.getParameter(INCLUDE_DESCRIPTION);
176176
boolean description = tmpStr != null && tmpStr.length() > 0;
@@ -204,9 +204,11 @@ public void doGet(HttpServletRequest request, HttpServletResponse response) thro
204204
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
205205
}
206206
} finally {
207-
if (beanWriter != null) beanWriter.close();
207+
if (beanWriter != null) {
208+
beanWriter.close();
209+
}
208210
if (jsonpcb != null) {
209-
writer.write(");");
211+
writer.write(");");
210212
}
211213
if (writer != null) {
212214
writer.close();

hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/AgeSnapshot.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,10 @@
2525
* Snapshot of block cache age in cache.
2626
* This object is preferred because we can control how it is serialized out when JSON'ing.
2727
*/
28-
@JsonIgnoreProperties({"ageHistogram", "snapshot"})
2928
public class AgeSnapshot {
3029

31-
private final FastLongHistogram ageHistogram;
32-
private final long[] quantiles;
30+
private transient final FastLongHistogram ageHistogram;
31+
private transient final long[] quantiles;
3332

3433
AgeSnapshot(final FastLongHistogram ageHistogram) {
3534
this.ageHistogram = ageHistogram;

hbase-server/src/main/java/org/apache/hadoop/hbase/io/hfile/BlockCacheUtil.java

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@
1717
*/
1818
package org.apache.hadoop.hbase.io.hfile;
1919

20-
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
21-
import com.fasterxml.jackson.core.JsonGenerationException;
22-
import com.fasterxml.jackson.databind.JsonMappingException;
23-
import com.fasterxml.jackson.databind.ObjectMapper;
24-
import com.fasterxml.jackson.databind.SerializationFeature;
2520
import java.io.IOException;
2621
import java.util.NavigableMap;
2722
import java.util.NavigableSet;
@@ -31,6 +26,13 @@
3126
import org.apache.hadoop.hbase.classification.InterfaceAudience;
3227
import org.apache.hadoop.conf.Configuration;
3328
import org.apache.hadoop.hbase.util.FastLongHistogram;
29+
import org.apache.hadoop.hbase.util.GsonUtil;
30+
31+
32+
import org.apache.hbase.thirdparty.com.google.gson.Gson;
33+
import org.apache.hbase.thirdparty.com.google.gson.TypeAdapter;
34+
import org.apache.hbase.thirdparty.com.google.gson.stream.JsonReader;
35+
import org.apache.hbase.thirdparty.com.google.gson.stream.JsonWriter;
3436

3537
/**
3638
* Utilty for aggregating counts in CachedBlocks and toString/toJSON CachedBlocks and BlockCaches.
@@ -41,12 +43,29 @@ public class BlockCacheUtil {
4143
/**
4244
* Needed generating JSON.
4345
*/
44-
private static final ObjectMapper MAPPER = new ObjectMapper();
45-
static {
46-
MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
47-
MAPPER.configure(SerializationFeature.FLUSH_AFTER_WRITE_VALUE, true);
48-
MAPPER.configure(SerializationFeature.INDENT_OUTPUT, true);
49-
}
46+
private static final Gson GSON = GsonUtil.createGson()
47+
.registerTypeAdapter(FastLongHistogram.class, new TypeAdapter<FastLongHistogram>() {
48+
49+
@Override
50+
public void write(JsonWriter out, FastLongHistogram value) throws IOException {
51+
AgeSnapshot snapshot = new AgeSnapshot(value);
52+
out.beginObject();
53+
out.name("mean").value(snapshot.getMean());
54+
out.name("min").value(snapshot.getMin());
55+
out.name("max").value(snapshot.getMax());
56+
out.name("75thPercentile").value(snapshot.get75thPercentile());
57+
out.name("95thPercentile").value(snapshot.get95thPercentile());
58+
out.name("98thPercentile").value(snapshot.get98thPercentile());
59+
out.name("99thPercentile").value(snapshot.get99thPercentile());
60+
out.name("999thPercentile").value(snapshot.get999thPercentile());
61+
out.endObject();
62+
}
63+
64+
@Override
65+
public FastLongHistogram read(JsonReader in) throws IOException {
66+
throw new UnsupportedOperationException();
67+
}
68+
}).setPrettyPrinting().create();
5069

5170
/**
5271
* @param cb
@@ -93,15 +112,10 @@ public String getFilename() {
93112
}
94113

95114
/**
96-
* @param filename
97-
* @param blocks
98115
* @return A JSON String of <code>filename</code> and counts of <code>blocks</code>
99-
* @throws JsonGenerationException
100-
* @throws JsonMappingException
101-
* @throws IOException
102116
*/
103117
public static String toJSON(final String filename, final NavigableSet<CachedBlock> blocks)
104-
throws JsonGenerationException, JsonMappingException, IOException {
118+
throws IOException {
105119
CachedBlockCountsPerFile counts = new CachedBlockCountsPerFile(filename);
106120
for (CachedBlock cb: blocks) {
107121
counts.count++;
@@ -112,31 +126,21 @@ public static String toJSON(final String filename, final NavigableSet<CachedBloc
112126
counts.sizeData += cb.getSize();
113127
}
114128
}
115-
return MAPPER.writeValueAsString(counts);
129+
return GSON.toJson(counts);
116130
}
117131

118132
/**
119-
* @param cbsbf
120133
* @return JSON string of <code>cbsf</code> aggregated
121-
* @throws JsonGenerationException
122-
* @throws JsonMappingException
123-
* @throws IOException
124134
*/
125-
public static String toJSON(final CachedBlocksByFile cbsbf)
126-
throws JsonGenerationException, JsonMappingException, IOException {
127-
return MAPPER.writeValueAsString(cbsbf);
135+
public static String toJSON(final CachedBlocksByFile cbsbf) throws IOException {
136+
return GSON.toJson(cbsbf);
128137
}
129138

130139
/**
131-
* @param bc
132140
* @return JSON string of <code>bc</code> content.
133-
* @throws JsonGenerationException
134-
* @throws JsonMappingException
135-
* @throws IOException
136141
*/
137-
public static String toJSON(final BlockCache bc)
138-
throws JsonGenerationException, JsonMappingException, IOException {
139-
return MAPPER.writeValueAsString(bc);
142+
public static String toJSON(final BlockCache bc) throws IOException {
143+
return GSON.toJson(bc);
140144
}
141145

142146
/**
@@ -172,7 +176,6 @@ public static CachedBlocksByFile getLoadedCachedBlocksByFile(final Configuration
172176
* This is different than metrics in that it is stats on current state of a cache.
173177
* See getLoadedCachedBlocksByFile
174178
*/
175-
@JsonIgnoreProperties({"cachedBlockStatsByFile"})
176179
public static class CachedBlocksByFile {
177180
private int count;
178181
private int dataBlockCount;
@@ -200,7 +203,7 @@ public static class CachedBlocksByFile {
200203
/**
201204
* Map by filename. use concurent utils because we want our Map and contained blocks sorted.
202205
*/
203-
private NavigableMap<String, NavigableSet<CachedBlock>> cachedBlockByFile =
206+
private transient NavigableMap<String, NavigableSet<CachedBlock>> cachedBlockByFile =
204207
new ConcurrentSkipListMap<String, NavigableSet<CachedBlock>>();
205208
FastLongHistogram hist = new FastLongHistogram();
206209

0 commit comments

Comments
 (0)