Skip to content

Commit 22dcf40

Browse files
Merge pull request #3988 from RedisInsight/bugfix/fe/java-ser-util-date
Fix #2667: Add support for java date serialization
2 parents 8483ef3 + b6f7e15 commit 22dcf40

File tree

7 files changed

+85
-44
lines changed

7 files changed

+85
-44
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@
235235
"gzip-js": "^0.3.2",
236236
"html-entities": "^2.3.2",
237237
"html-react-parser": "^1.2.4",
238-
"java-object-serialization": "^0.1.1",
238+
"java-object-serialization": "^0.1.2",
239239
"js-yaml": "^4.1.0",
240240
"json-bigint": "^1.0.0",
241241
"jsonpath": "^1.1.1",

redisinsight/ui/src/utils/formatters/bufferFormatters.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ObjectInputStream } from 'java-object-serialization'
33
import { TextDecoder, TextEncoder } from 'text-encoding'
44
import { Buffer } from 'buffer'
55
import { KeyValueFormat } from 'uiSrc/constants'
6+
import JavaDate from './java-date'
67
// eslint-disable-next-line import/order
78
import {
89
RedisResponseBuffer,
@@ -12,6 +13,8 @@ import {
1213
} from 'uiSrc/slices/interfaces'
1314
import { Nullable } from '../types'
1415

16+
ObjectInputStream.RegisterObjectClass(JavaDate, JavaDate.ClassName, JavaDate.SerialVersionUID)
17+
1518
const decoder = new TextDecoder('utf-8')
1619
const encoder = new TextEncoder()
1720

@@ -171,6 +174,10 @@ const bufferToJava = (reply: RedisResponseBuffer) => {
171174
return decoded
172175
}
173176

177+
if (decoded instanceof Date) {
178+
return decoded
179+
}
180+
174181
const { fields } = decoded
175182
const fieldsArray = Array.from(fields, ([key, value]) => ({ [key]: value }))
176183
return { ...decoded, fields: fieldsArray }
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { ObjectInputStream, JavaSerializable } from 'java-object-serialization'
2+
3+
export default class JavaDate implements JavaSerializable {
4+
// The class name in the serialized data
5+
static readonly ClassName = 'java.util.Date'
6+
7+
// The serial version UID followed for 'java.util.Date'
8+
static readonly SerialVersionUID = '7523967970034938905'
9+
10+
// The maximum value for a Java long
11+
readonly JAVA_MAX_LONG = 9223372036854775807n // 2^63 - 1
12+
13+
// The maximum value for a two's complement long
14+
readonly TWO_COMPLEMENT_MAX_LONG = 18446744073709551616n // 2^64
15+
16+
time: bigint = 0n
17+
18+
readObject(stream: ObjectInputStream): void {
19+
this.time = stream.readLong()
20+
}
21+
22+
readResolve() {
23+
let timeValue: number
24+
25+
// Handle two's complement conversion for negative numbers
26+
if (this.time > this.JAVA_MAX_LONG) {
27+
// If the number is larger than MAX_LONG, it's a negative number in two's complement
28+
timeValue = Number(this.time - this.TWO_COMPLEMENT_MAX_LONG)
29+
} else {
30+
timeValue = Number(this.time)
31+
}
32+
33+
const date = new Date(timeValue)
34+
35+
// Validate the date
36+
if (Number.isNaN(date.getTime())) {
37+
throw new Error(`Invalid date value: ${timeValue} (original: ${this.time})`)
38+
}
39+
40+
return date
41+
}
42+
}

redisinsight/ui/src/utils/tests/formatters/bufferFormatters.spec.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { input } from '@testing-library/user-event/dist/types/event'
22
import { RedisResponseBufferType } from 'uiSrc/slices/interfaces'
3+
import JavaDate from 'uiSrc/utils/formatters/java-date'
34
import {
45
bufferToString,
56
anyToBuffer,
@@ -16,6 +17,12 @@ import {
1617
bufferToUint8Array,
1718
} from 'uiSrc/utils'
1819

20+
try {
21+
// Register JavaDate class for deserialization
22+
ObjectInputStream.RegisterObjectClass(JavaDate, JavaDate.ClassName, JavaDate.SerialVersionUID)
23+
// eslint-disable-next-line no-empty
24+
} catch (e) {}
25+
1926
const defaultValues = [
2027
{ unicode: 'test', ascii: 'test', hex: '74657374', uint8Array: [116, 101, 115, 116], binary: '01110100011001010111001101110100' },
2128
{ unicode: 'test test', ascii: 'test test', hex: '746573742074657374', uint8Array: [116, 101, 115, 116, 32, 116, 101, 115, 116], binary: '011101000110010101110011011101000010000001110100011001010111001101110100' },
@@ -134,6 +141,7 @@ describe('binaryToBuffer', () => {
134141
const javaValues = [
135142
{ uint8Array: [172, 237, 0, 5, 115, 114, 0, 8, 69, 109, 112, 108, 111, 121, 101, 101, 2, 94, 116, 52, 103, 198, 18, 60, 2, 0, 3, 73, 0, 6, 110, 117, 109, 98, 101, 114, 76, 0, 7, 97, 100, 100, 114, 101, 115, 115, 116, 0, 18, 76, 106, 97, 118, 97, 47, 108, 97, 110, 103, 47, 83, 116, 114, 105, 110, 103, 59, 76, 0, 4, 110, 97, 109, 101, 113, 0, 126, 0, 1, 120, 112, 0, 0, 0, 101, 116, 0, 25, 80, 104, 111, 107, 107, 97, 32, 75, 117, 97, 110, 44, 32, 65, 109, 98, 101, 104, 116, 97, 32, 80, 101, 101, 114, 116, 0, 9, 82, 101, 121, 97, 110, 32, 65, 108, 105], value: { annotations: [], className: 'Employee', fields: [{ number: 101 }, { address: 'Phokka Kuan, Ambehta Peer' }, { name: 'Reyan Ali' }], serialVersionUid: 170701604314812988n } },
136143
{ uint8Array: [172, 237, 0, 5, 115, 114, 0, 32, 115, 101, 114, 105, 97, 108, 105, 122, 97, 116, 105, 111, 110, 68, 101, 109, 111, 46, 65, 110, 110, 111, 116, 97, 116, 105, 111, 110, 84, 101, 115, 116, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 1, 73, 0, 6, 110, 117, 109, 98, 101, 114, 120, 112, 0, 0, 0, 90], value: { annotations: [], className: 'serializationDemo.AnnotationTest', fields: [{ number: 90 }], serialVersionUid: 2n } },
144+
{ uint8Array: [ 172, 237, 0, 5, 115, 114, 0, 14, 106, 97, 118, 97, 46, 117, 116, 105, 108, 46, 68, 97, 116, 101, 104, 106, 129, 1, 75, 89, 116, 25, 3, 0, 0, 120, 112, 119, 8, 0, 0, 1, 146, 226, 121, 165, 136, 120, ], value: new Date(Number(1730376476040n)) },
137145
]
138146

139147
const getBufferToJavaTests = javaValues.map(({ uint8Array, value }) =>
@@ -150,3 +158,4 @@ describe('bufferToUint8Array', () => {
150158
expect(bufferToUint8Array(anyToBuffer(uint8Array))).toEqual(new Uint8Array(uint8Array))
151159
})
152160
})
161+

tests/e2e/tests/web/regression/browser/add-keys.e2e.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ test('Verify that user can add json with BigInt', async t => {
121121
await t.click(browserPage.addKeyButton);
122122

123123
await t.click(browserPage.editJsonObjectButton);
124-
await t.expect(await browserPage.jsonValueInput.textContent).contains('result', 'edit value is empty');
124+
await t.expect(await browserPage.jsonValueInput.textContent).contains('message', 'edit value is empty');
125125
await t.click(browserPage.cancelEditButton);
126126

127127
await t.click(browserPage.expandJsonObject);

tests/e2e/tests/web/regression/browser/formatters.e2e.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,18 +27,14 @@ fixture `Formatters`
2727
.beforeEach(async() => {
2828
await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneV8Config);
2929

30-
await populateHashWithFields(ossStandaloneV8Config.host, ossStandaloneV8Config.port, keyToAddParameters);
3130
})
3231
.afterEach(async() => {
3332
// Clear keys and database
3433
await apiKeyRequests.deleteKeyByNameApi(keyName, ossStandaloneV8Config.databaseName);
3534
await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneV8Config);
3635
});
3736

38-
test.before(async t => {
39-
await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneV8Config);
40-
41-
})('Verify that UTF8 in PHP serialized', async t => {
37+
test('Verify that UTF8 in PHP serialized', async t => {
4238
const phpValueChinese = '测试';
4339
const phpValueCRussian = 'Привет мир!';
4440
const setValue =`SET ${keyName} "a:3:{s:4:\\"name\\";s:6:\\"${phpValueChinese}\\";s:3:\\"age\\";i:30;s:7:\\"message\\";s:20:\\"${phpValueCRussian}\\";}"\n`;
@@ -51,3 +47,15 @@ test.before(async t => {
5147
await t.expect(await browserPage.getStringKeyValue()).contains(phpValueChinese, 'data is not serialized in php');
5248
await t.expect(await browserPage.getStringKeyValue()).contains(phpValueCRussian, 'data is not serialized in php');
5349
});
50+
51+
test('Verify that dataTime is displayed in Java serialized', async t => {
52+
const hexValue ='ACED00057372000E6A6176612E7574696C2E44617465686A81014B59741903000078707708000000BEACD0567278';
53+
const javaTimeValue = '"1995-12-14T12:12:01.010Z"'
54+
55+
await browserPage.addHashKey(keyName);
56+
// Add valid value in HEX format for convertion
57+
await browserPage.selectFormatter('HEX');
58+
await browserPage.editHashKeyValue(hexValue);
59+
await browserPage.selectFormatter('Java serialized');
60+
await t.expect(browserPage.hashFieldValue.innerText).eql(javaTimeValue, 'data is not serialized in java');
61+
});

yarn.lock

Lines changed: 12 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8252,12 +8252,12 @@ jake@^10.8.5:
82528252
filelist "^1.0.1"
82538253
minimatch "^3.0.4"
82548254

8255-
java-object-serialization@^0.1.1:
8256-
version "0.1.1"
8257-
resolved "https://registry.yarnpkg.com/java-object-serialization/-/java-object-serialization-0.1.1.tgz#b20f34a619df3ce4b58980d7d9893048a696a0bd"
8258-
integrity sha512-m1bd/kPwNjbrMrIITzMGWoXiSU5fzUg6IdzGDrmGNPahNQ5YVzY9dv5qQzAcRC7oy0C0CwDseatdeI6SKO8MLA==
8255+
java-object-serialization@^0.1.2:
8256+
version "0.1.2"
8257+
resolved "https://registry.yarnpkg.com/java-object-serialization/-/java-object-serialization-0.1.2.tgz#229ee4b70ea89e72206e32a826afacd09d9badfd"
8258+
integrity sha512-l0V2a/E7r6ScqG+ne09KR7G1npbiVdDf3Vdk6fcn8jy5TQiTTOQbDg9OfBriv2NmnCxcm4NmFW2dAD9QaN/htw==
82598259
dependencies:
8260-
tslib "^2.1.0"
8260+
tslib "^2.8.0"
82618261

82628262
jest-changed-files@^29.7.0:
82638263
version "29.7.0"
@@ -12563,16 +12563,7 @@ string-length@^4.0.1:
1256312563
char-regex "^1.0.2"
1256412564
strip-ansi "^6.0.0"
1256512565

12566-
"string-width-cjs@npm:string-width@^4.2.0":
12567-
version "4.2.3"
12568-
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
12569-
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
12570-
dependencies:
12571-
emoji-regex "^8.0.0"
12572-
is-fullwidth-code-point "^3.0.0"
12573-
strip-ansi "^6.0.1"
12574-
12575-
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
12566+
"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
1257612567
version "4.2.3"
1257712568
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
1257812569
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@@ -12677,14 +12668,7 @@ stringify-object@^3.3.0:
1267712668
is-obj "^1.0.1"
1267812669
is-regexp "^1.0.0"
1267912670

12680-
"strip-ansi-cjs@npm:strip-ansi@^6.0.1":
12681-
version "6.0.1"
12682-
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
12683-
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
12684-
dependencies:
12685-
ansi-regex "^5.0.1"
12686-
12687-
strip-ansi@^6.0.0, strip-ansi@^6.0.1:
12671+
"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
1268812672
version "6.0.1"
1268912673
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
1269012674
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
@@ -13157,10 +13141,10 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.3:
1315713141
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
1315813142
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
1315913143

13160-
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1:
13161-
version "2.5.0"
13162-
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf"
13163-
integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==
13144+
tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.1, tslib@^2.8.0:
13145+
version "2.8.1"
13146+
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f"
13147+
integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==
1316413148

1316513149
tsutils@^3.21.0:
1316613150
version "3.21.0"
@@ -14022,7 +14006,7 @@ [email protected], word-wrap@^1.2.3, word-wrap@~1.2.3:
1402214006
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f"
1402314007
integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==
1402414008

14025-
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
14009+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0:
1402614010
version "7.0.0"
1402714011
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
1402814012
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
@@ -14040,15 +14024,6 @@ wrap-ansi@^6.2.0:
1404014024
string-width "^4.1.0"
1404114025
strip-ansi "^6.0.0"
1404214026

14043-
wrap-ansi@^7.0.0:
14044-
version "7.0.0"
14045-
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43"
14046-
integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==
14047-
dependencies:
14048-
ansi-styles "^4.0.0"
14049-
string-width "^4.1.0"
14050-
strip-ansi "^6.0.0"
14051-
1405214027
wrap-ansi@^8.1.0:
1405314028
version "8.1.0"
1405414029
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"

0 commit comments

Comments
 (0)