Skip to content

Commit 21fbf4b

Browse files
committed
Following changes:
# Upgraded Jackson # When deserializing a 'Result', use first (latest) entry instead of last entry. # Moved codec initialization from clinit to init # Avoid multiple class validations # Minor improvements to test cases
1 parent d3a57cf commit 21fbf4b

File tree

10 files changed

+72
-57
lines changed

10 files changed

+72
-57
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ Add below entry within the `dependencies` section of your `pom.xml`:
412412
<dependency>
413413
<groupId>com.flipkart</groupId>
414414
<artifactId>hbase-object-mapper</artifactId>
415-
<version>1.14.1</version>
415+
<version>1.15</version>
416416
</dependency>
417417
```
418418

@@ -423,7 +423,7 @@ See artifact details: [com.flipkart:hbase-object-mapper on **Maven Central**](ht
423423
To build this project, follow below simple steps:
424424

425425
1. Do a `git clone` of this repository
426-
2. Checkout latest stable version `git checkout v1.14.1`
426+
2. Checkout latest stable version `git checkout v1.15`
427427
3. Execute `mvn clean install` from shell
428428

429429
### Please note:

pom.xml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<modelVersion>4.0.0</modelVersion>
1212
<groupId>com.flipkart</groupId>
1313
<artifactId>hbase-object-mapper</artifactId>
14-
<version>1.14.1</version>
14+
<version>1.15</version>
1515
<url>https://github.com/flipkart-incubator/hbase-orm</url>
1616
<scm>
1717
<url>https://github.com/flipkart-incubator/hbase-orm</url>
@@ -64,7 +64,7 @@
6464
<dependency>
6565
<groupId>com.fasterxml.jackson.core</groupId>
6666
<artifactId>jackson-databind</artifactId>
67-
<version>2.9.10.3</version>
67+
<version>2.9.10.4</version>
6868
</dependency>
6969
<dependency>
7070
<groupId>com.google.guava</groupId>
@@ -75,7 +75,7 @@
7575
<dependency>
7676
<groupId>org.projectlombok</groupId>
7777
<artifactId>lombok</artifactId>
78-
<version>1.18.10</version>
78+
<version>1.18.12</version>
7979
<scope>test</scope>
8080
</dependency>
8181
<dependency>

src/main/java/com/flipkart/hbaseobjectmapper/AbstractHBDAO.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ protected AbstractHBDAO(Configuration configuration) throws IOException {
139139
public T get(R rowKey, int numVersionsToFetch) throws IOException {
140140
try (Table table = getHBaseTable()) {
141141
Result result = table.get(new Get(toBytes(rowKey)).readVersions(numVersionsToFetch));
142-
return hbObjectMapper.readValue(rowKey, result, hbRecordClass);
142+
return hbObjectMapper.readValueFromResult(result, hbRecordClass);
143143
}
144144
}
145145

@@ -177,7 +177,7 @@ public Get getGet(R rowKey) {
177177
public T getOnGet(Get get) throws IOException {
178178
try (Table table = getHBaseTable()) {
179179
Result result = table.get(get);
180-
return hbObjectMapper.readValue(result, hbRecordClass);
180+
return hbObjectMapper.readValueFromResult(result, hbRecordClass);
181181
}
182182
}
183183

@@ -192,7 +192,7 @@ public List<T> getOnGets(List<Get> gets) throws IOException {
192192
try (Table table = getHBaseTable()) {
193193
Result[] results = table.get(gets);
194194
for (Result result : results) {
195-
records.add(hbObjectMapper.readValue(result, hbRecordClass));
195+
records.add(hbObjectMapper.readValueFromResult(result, hbRecordClass));
196196
}
197197
}
198198
return records;
@@ -216,7 +216,7 @@ public T[] get(R[] rowKeys, int numVersionsToFetch) throws IOException {
216216
try (Table table = getHBaseTable()) {
217217
Result[] results = table.get(gets);
218218
for (int i = 0; i < records.length; i++) {
219-
records[i] = hbObjectMapper.readValue(rowKeys[i], results[i], hbRecordClass);
219+
records[i] = hbObjectMapper.readValueFromResult(results[i], hbRecordClass);
220220
}
221221
}
222222
return records;
@@ -250,7 +250,7 @@ public List<T> get(List<R> rowKeys, int numVersionsToFetch) throws IOException {
250250
try (Table table = getHBaseTable()) {
251251
Result[] results = table.get(gets);
252252
for (Result result : results) {
253-
records.add(hbObjectMapper.readValue(result, hbRecordClass));
253+
records.add(hbObjectMapper.readValueFromResult(result, hbRecordClass));
254254
}
255255
}
256256
return records;
@@ -323,7 +323,7 @@ public List<T> get(Scan scan) throws IOException {
323323
try (Table table = getHBaseTable();
324324
ResultScanner scanner = table.getScanner(scan)) {
325325
for (Result result : scanner) {
326-
records.add(hbObjectMapper.readValue(result, hbRecordClass));
326+
records.add(hbObjectMapper.readValueFromResult(result, hbRecordClass));
327327
}
328328
}
329329
return records;
@@ -518,7 +518,7 @@ public Increment getIncrement(R rowKey) {
518518
public T increment(Increment increment) throws IOException {
519519
try (Table table = getHBaseTable()) {
520520
Result result = table.increment(increment);
521-
return hbObjectMapper.readValue(result, hbRecordClass);
521+
return hbObjectMapper.readValueFromResult(result, hbRecordClass);
522522
}
523523
}
524524

@@ -569,7 +569,7 @@ public T append(R rowKey, Map<String, Object> valuesToAppend) throws IOException
569569
}
570570
try (Table table = getHBaseTable()) {
571571
Result result = table.append(append);
572-
return hbObjectMapper.readValue(result, hbRecordClass);
572+
return hbObjectMapper.readValueFromResult(result, hbRecordClass);
573573
}
574574
}
575575

@@ -599,7 +599,7 @@ public Append getAppend(R rowKey) {
599599
public T append(Append append) throws IOException {
600600
try (Table table = getHBaseTable()) {
601601
Result result = table.append(append);
602-
return hbObjectMapper.readValue(result, hbRecordClass);
602+
return hbObjectMapper.readValueFromResult(result, hbRecordClass);
603603
}
604604
}
605605

@@ -623,7 +623,7 @@ public List<T> get(R startRowKey, R endRowKey) throws IOException {
623623
* @throws IOException When HBase call fails
624624
*/
625625
public R persist(HBRecord<R> record) throws IOException {
626-
Put put = hbObjectMapper.writeValueAsPut(record);
626+
Put put = hbObjectMapper.writeValueAsPut0(record);
627627
try (Table table = getHBaseTable()) {
628628
table.put(put);
629629
return record.composeRowKey();
@@ -640,9 +640,9 @@ public R persist(HBRecord<R> record) throws IOException {
640640
public List<R> persist(List<T> records) throws IOException {
641641
List<Put> puts = new ArrayList<>(records.size());
642642
List<R> rowKeys = new ArrayList<>(records.size());
643-
for (HBRecord<R> object : records) {
644-
puts.add(hbObjectMapper.writeValueAsPut(object));
645-
rowKeys.add(object.composeRowKey());
643+
for (HBRecord<R> record : records) {
644+
puts.add(hbObjectMapper.writeValueAsPut0(record));
645+
rowKeys.add(record.composeRowKey());
646646
}
647647
try (Table table = getHBaseTable()) {
648648
table.put(puts);

src/main/java/com/flipkart/hbaseobjectmapper/HBObjectMapper.java

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,6 @@
3737
*/
3838
public class HBObjectMapper {
3939

40-
private static final Codec DEFAULT_CODEC = new BestSuitCodec();
41-
4240
private final Codec codec;
4341

4442
/**
@@ -60,7 +58,7 @@ public HBObjectMapper(Codec codec) {
6058
* @see #HBObjectMapper(Codec)
6159
*/
6260
public HBObjectMapper() {
63-
this(DEFAULT_CODEC);
61+
this(new BestSuitCodec());
6462
}
6563

6664
/**
@@ -88,7 +86,10 @@ <R extends Serializable & Comparable<R>, T extends HBRecord<R>> R bytesToRowKey(
8886
*
8987
* @see #convertRecordToMap(HBRecord)
9088
*/
91-
private <R extends Serializable & Comparable<R>, T extends HBRecord<R>> T convertMapToRecord(byte[] rowKeyBytes, NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map, Class<T> clazz) {
89+
private <R extends Serializable & Comparable<R>, T extends HBRecord<R>> T convertMapToRecord(
90+
byte[] rowKeyBytes,
91+
NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map,
92+
Class<T> clazz) {
9293
Collection<Field> fields = getHBColumnFields0(clazz).values();
9394
WrappedHBTable<R, T> hbTable = new WrappedHBTable<>(clazz);
9495
R rowKey = bytesToRowKey(rowKeyBytes, hbTable.getCodecFlags(), clazz);
@@ -115,8 +116,8 @@ record = clazz.getDeclaredConstructor()
115116
if (columnVersionsMap == null || columnVersionsMap.isEmpty()) {
116117
continue;
117118
}
118-
Map.Entry<Long, byte[]> lastEntry = columnVersionsMap.lastEntry();
119-
objectSetFieldValue(record, field, lastEntry.getValue(), hbColumn.codecFlags());
119+
Map.Entry<Long, byte[]> firstEntry = columnVersionsMap.firstEntry();
120+
objectSetFieldValue(record, field, firstEntry.getValue(), hbColumn.codecFlags());
120121
} else {
121122
objectSetFieldValue(record, field, columnVersionsMap, hbColumn.codecFlags());
122123
}
@@ -253,7 +254,8 @@ private void validateHBColumnField(Field field) {
253254
* @see #convertMapToRecord(byte[], NavigableMap, Class)
254255
*/
255256
@SuppressWarnings("unchecked")
256-
private <R extends Serializable & Comparable<R>, T extends HBRecord<R>> NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> convertRecordToMap(HBRecord<R> record) {
257+
private <R extends Serializable & Comparable<R>, T extends HBRecord<R>>
258+
NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> convertRecordToMap(HBRecord<R> record) {
257259
Class<T> clazz = (Class<T>) record.getClass();
258260
Collection<Field> fields = getHBColumnFields0(clazz).values();
259261
NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> map = new TreeMap<>(Bytes.BYTES_COMPARATOR);
@@ -341,6 +343,10 @@ private <R extends Serializable & Comparable<R>> NavigableMap<Long, byte[]> getF
341343
@SuppressWarnings("unchecked")
342344
public <R extends Serializable & Comparable<R>, T extends HBRecord<R>> Put writeValueAsPut(HBRecord<R> record) {
343345
validateHBClass((Class<T>) record.getClass());
346+
return writeValueAsPut0(record);
347+
}
348+
349+
<R extends Serializable & Comparable<R>> Put writeValueAsPut0(HBRecord<R> record) {
344350
Put put = new Put(composeRowKey(record));
345351
for (Map.Entry<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> fe : convertRecordToMap(record).entrySet()) {
346352
byte[] family = fe.getKey();
@@ -456,18 +462,13 @@ public <R extends Serializable & Comparable<R>, T extends HBRecord<R>> T readVal
456462
return readValueFromResult(result, clazz);
457463
}
458464

459-
<R extends Serializable & Comparable<R>, T extends HBRecord<R>> T readValue(R rowKey, Result result, Class<T> clazz) {
460-
if (rowKey == null)
461-
return readValueFromResult(result, clazz);
462-
else
463-
return readValueFromRowAndResult(rowKeyToBytes(rowKey, WrappedHBTable.getCodecFlags(clazz)), result, clazz);
464-
}
465-
466465
private boolean isResultEmpty(Result result) {
467-
return result == null || result.isEmpty() || result.getRow() == null || result.getRow().length == 0;
466+
if (result == null || result.isEmpty()) return true;
467+
byte[] rowBytes = result.getRow();
468+
return rowBytes == null || rowBytes.length == 0;
468469
}
469470

470-
private <R extends Serializable & Comparable<R>, T extends HBRecord<R>> T readValueFromResult(Result result, Class<T> clazz) {
471+
<R extends Serializable & Comparable<R>, T extends HBRecord<R>> T readValueFromResult(Result result, Class<T> clazz) {
471472
if (isResultEmpty(result)) return null;
472473
return convertMapToRecord(result.getRow(), result.getMap(), clazz);
473474
}

src/main/java/com/flipkart/hbaseobjectmapper/HBObjectMapperFactory.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,16 @@ private HBObjectMapperFactory() {
1313
/**
1414
* Default instance of {@link HBObjectMapper}
1515
*/
16-
private static final HBObjectMapper hbObjectMapper = new HBObjectMapper();
16+
private static HBObjectMapper hbObjectMapper;
17+
private static final Object[] lock = new Object[0];
1718

1819
static HBObjectMapper construct(Codec codec) {
19-
return codec == null ? hbObjectMapper : new HBObjectMapper(codec);
20+
if (hbObjectMapper == null) {
21+
synchronized (lock) {
22+
hbObjectMapper = codec == null ? new HBObjectMapper() : new HBObjectMapper(codec);
23+
}
24+
}
25+
return hbObjectMapper;
2026
}
2127
}
2228

src/main/java/com/flipkart/hbaseobjectmapper/codec/BestSuitCodec.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.flipkart.hbaseobjectmapper.codec;
22

3-
import com.fasterxml.jackson.databind.DeserializationFeature;
4-
import com.fasterxml.jackson.databind.JavaType;
5-
import com.fasterxml.jackson.databind.ObjectMapper;
3+
import com.fasterxml.jackson.databind.*;
64
import com.flipkart.hbaseobjectmapper.Flag;
75
import com.flipkart.hbaseobjectmapper.codec.exceptions.DeserializationException;
86
import com.flipkart.hbaseobjectmapper.codec.exceptions.SerializationException;

src/test/java/com/flipkart/hbaseobjectmapper/testcases/TestHBObjectMapper.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -213,13 +213,13 @@ public void testInvalidObjects() {
213213
String errorMessage = "An object with " + p.getSecond() + " should've thrown an " + p.getThird().getName();
214214
try {
215215
hbMapper.writeValueAsResult(record);
216-
fail(errorMessage + " while converting bean to Result\nFailing object = " + record);
216+
fail(String.format("%s while converting bean to Result%nFailing object = %s", errorMessage, record));
217217
} catch (IllegalArgumentException ex) {
218218
assertEquals(p.getThird(), ex.getClass(), "Mismatch in type of exception thrown");
219219
}
220220
try {
221221
hbMapper.writeValueAsPut(record);
222-
fail(errorMessage + " while converting bean to Put\nFailing object = " + record);
222+
fail(String.format("%s while converting bean to Put%nFailing object = %s", errorMessage, record));
223223
} catch (IllegalArgumentException ex) {
224224
assertEquals(p.getThird(), ex.getClass(), "Mismatch in type of exception thrown");
225225
}
@@ -324,22 +324,24 @@ public void testUninstantiatableClass() {
324324

325325
@Test
326326
public void testHBColumnMultiVersion() {
327-
Double[] testNumbers = new Double[]{3.14159, 2.71828, 0.0};
328-
for (Double n : testNumbers) {
327+
Double[] numbers = new Double[]{0.0, 3.14159, 2.71828};
328+
for (Double number : numbers) {
329329
// Written as unversioned, read as versioned
330-
Result result = hbMapper.writeValueAsResult(new CrawlNoVersion("key").setF1(n));
330+
Result result = hbMapper.writeValueAsResult(new CrawlNoVersion("key").setF1(number));
331331
Crawl versioned = hbMapper.readValue(result, Crawl.class);
332332
NavigableMap<Long, Double> columnHistory = versioned.getF1();
333333
assertEquals(1, columnHistory.size(), "Column history size mismatch");
334-
assertEquals(n, columnHistory.lastEntry().getValue(), String.format("Inconsistency between %s and %s", HBColumn.class.getSimpleName(), HBColumnMultiVersion.class.getSimpleName()));
334+
assertEquals(number, columnHistory.lastEntry().getValue(), String.format("Inconsistency between %s and %s",
335+
HBColumn.class.getSimpleName(), HBColumnMultiVersion.class.getSimpleName()));
335336
// Written as versioned, read as unversioned
336-
Crawl key = new Crawl("key").addF1(Double.MAX_VALUE).addF1(Double.MAX_VALUE).addF1(Double.MAX_VALUE);
337-
Crawl versionedCrawl = key.addF1(n);
338-
Result result1 = hbMapper.writeValueAsResult(versionedCrawl);
339-
CrawlNoVersion unversionedCrawl = hbMapper.readValue(result1, CrawlNoVersion.class);
340-
Double f1 = unversionedCrawl.getF1();
341-
System.out.println(unversionedCrawl);
342-
assertEquals(n, f1, String.format("Inconsistency between %s and %s\nVersioned (persisted) object = %s\nUnversioned (retrieved) object = %s ", HBColumnMultiVersion.class.getSimpleName(), HBColumn.class.getSimpleName(), versionedCrawl, unversionedCrawl));
337+
Crawl crawl = new Crawl("key").addF1(Double.MAX_VALUE).addF1(Double.MAX_VALUE).addF1(Double.MAX_VALUE);
338+
Crawl versionedCrawl = crawl.addF1(number);
339+
Result crawlAsResult = hbMapper.writeValueAsResult(versionedCrawl);
340+
CrawlNoVersion unversionedCrawl = hbMapper.readValue(crawlAsResult, CrawlNoVersion.class);
341+
assertEquals(number, unversionedCrawl.getF1(), String.format("Inconsistency between %s and %s%n" +
342+
"Versioned (persisted) object = %s%nUnversioned (retrieved) object = %s",
343+
HBColumnMultiVersion.class.getSimpleName(), HBColumn.class.getSimpleName(),
344+
versionedCrawl, unversionedCrawl));
343345
}
344346
}
345347
}

src/test/java/com/flipkart/hbaseobjectmapper/testcases/TestsAbstractHBDAO.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ public static void setup() {
4747
fail("The environmental variable " + InMemoryHBaseCluster.INMEMORY_CLUSTER_START_TIMEOUT + " is specified incorrectly (Must be numeric)");
4848
} catch (Exception e) {
4949
e.printStackTrace(System.err);
50-
fail("Failed to connect to HBase. Aborted execution of DAO-related test cases. Reason:\n" + e.getMessage());
50+
fail(String.format("Failed to connect to HBase. Aborted execution of DAO-related test cases." +
51+
"Reason:%n%s", e.getMessage()));
5152
}
5253
}
5354

@@ -107,9 +108,9 @@ public void testCRUD() throws IOException {
107108
final List<Citizen> records = TestObjects.validCitizenObjects;
108109
assertEquals("citizens", citizenDao.getTableName());
109110
final Set<String> columnFamiliesCitizen = citizenDao.getColumnFamiliesAndVersions().keySet(), columnFamiliesCitizenSummary = citizenSummaryDAO.getColumnFamiliesAndVersions().keySet();
110-
assertEquals(s("main", "optional"), columnFamiliesCitizen, "Issue with column families of 'citizens' table\n" + columnFamiliesCitizen);
111+
assertEquals(s("main", "optional"), columnFamiliesCitizen, "Issue with column families of 'citizens' table%n" + columnFamiliesCitizen);
111112
assertEquals("citizens_summary", citizenSummaryDAO.getTableName());
112-
assertEquals(s("a"), columnFamiliesCitizenSummary, "Issue with column families of 'citizens_summary' table\n" + columnFamiliesCitizenSummary);
113+
assertEquals(s("a"), columnFamiliesCitizenSummary, "Issue with column families of 'citizens_summary' table%n" + columnFamiliesCitizenSummary);
113114
String[] allRowKeys = new String[records.size()];
114115
Map<String, Map<String, Object>> expectedFieldValues = new HashMap<>();
115116
for (int i = 0; i < records.size(); i++) { // for each test object,
@@ -358,7 +359,7 @@ public void testVersioning() throws IOException {
358359
rowKeysList.add(key);
359360
}
360361
}
361-
String[] rowKeys = rowKeysList.toArray(new String[rowKeysList.size()]);
362+
String[] rowKeys = rowKeysList.toArray(new String[0]);
362363

363364
Set<Double> oldestValuesRangeScan = new HashSet<>(), oldestValuesBulkScan = new HashSet<>();
364365
for (int k = 1; k <= NUM_VERSIONS; k++) {

src/test/java/com/flipkart/hbaseobjectmapper/testcases/entities/Crawl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import java.util.NavigableMap;
77
import java.util.TreeMap;
8+
import java.util.concurrent.TimeUnit;
89

910
@HBTable(name = "crawls", families = {@Family(name = "a", versions = 10)})
1011
@ToString
@@ -34,6 +35,10 @@ public void parseRowKey(String rowKey) {
3435
}
3536

3637
public Crawl addF1(Double f1) {
38+
try {
39+
TimeUnit.MILLISECONDS.sleep(10);
40+
} catch (InterruptedException ignored) {
41+
}
3742
this.f1.put(System.currentTimeMillis(), f1);
3843
return this;
3944
}

src/test/java/com/flipkart/hbaseobjectmapper/testcases/util/cluster/InMemoryHBaseCluster.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package com.flipkart.hbaseobjectmapper.testcases.util.cluster;
22

33
import org.apache.hadoop.hbase.HBaseTestingUtility;
4-
import org.apache.hadoop.hbase.MiniHBaseCluster;
54
import org.apache.hadoop.hbase.client.Connection;
65

76
import java.io.IOException;
@@ -44,6 +43,9 @@ public Connection start() throws IOException {
4443
throw new IOException("Error starting an in-memory HBase cluster", e);
4544
}
4645
connection = utility.getConnection();
46+
if (connection == null) {
47+
throw new IllegalStateException("Connection could not be established with in-memory HBase cluster");
48+
}
4749
return connection;
4850
}
4951

0 commit comments

Comments
 (0)