Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions src/JsonProperty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ReflectMetaDataKeys } from './common'
type Params<P> = {
path?: string
paths?: string[]
pathAlternatives?: string[]
required?: boolean
type?:
| (new (...args: any[]) => P)
Expand Down Expand Up @@ -53,11 +54,13 @@ export default function JsonProperty<P = unknown>(
params.type || Reflect.getMetadata('design:type', target, propertyName),
}

const existingMetadata: Record<string, JsonPropertyMetadata<P>> =
Reflect.getMetadata(
ReflectMetaDataKeys.TsJacksonJsonProperty,
target.constructor
) || {}
const existingMetadata: Record<
string,
JsonPropertyMetadata<P>
> = Reflect.getMetadata(
ReflectMetaDataKeys.TsJacksonJsonProperty,
target.constructor
) || {}

existingMetadata[propertyName] = metadata

Expand Down
22 changes: 22 additions & 0 deletions src/deserialize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,28 @@ describe('deserialize', () => {
)
})

test('Class with path alternatives', () => {
@Serializable()
class TestClass {
@JsonProperty({ pathAlternatives: ['treat', 'goodie'] })
snack: string
}

const jsonTreat = {
treat: 'Scooby Snack',
}

const jsonGoodie = {
goodie: 'Sandwich',
}
const expected = new TestClass()
expected.snack = jsonTreat.treat
expect(deserialize(jsonTreat, TestClass)).toStrictEqual(expected)

expected.snack = jsonGoodie.goodie
expect(deserialize(jsonGoodie, TestClass)).toStrictEqual(expected)
})

test('Class with one to one relation', () => {
@Serializable()
class Dog {
Expand Down
29 changes: 19 additions & 10 deletions src/deserialize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,11 @@ export default function deserialize<T, U extends Array<unknown>>(
...args: U
): T {
assertSerializable(serializableClass)
const propsMetadata: Record<
string,
JsonPropertyMetadata
> = Reflect.getMetadata(
ReflectMetaDataKeys.TsJacksonJsonProperty,
serializableClass
)
const propsMetadata: Record<string, JsonPropertyMetadata> =
Reflect.getMetadata(
ReflectMetaDataKeys.TsJacksonJsonProperty,
serializableClass
)
const resultClass = new serializableClass(...args)
const jsonObject = typeof json === 'string' ? JSON.parse(json) : json
const propertiesAfterDeserialize: {
Expand All @@ -44,9 +42,7 @@ export default function deserialize<T, U extends Array<unknown>>(
afterDeserialize: JsonPropertyMetadata['afterDeserialize']
}[] = []
for (const [propName, propParams] of Object.entries(propsMetadata)) {
const jsonValue = propParams.paths
? propParams.paths.map((path) => get(jsonObject, path))
: get(jsonObject, propParams.path)
const jsonValue = evaluateJsonValueByPath(jsonObject, propParams)
propParams.required &&
assertRequired({
json: jsonObject,
Expand Down Expand Up @@ -136,3 +132,16 @@ function deserializeProperty(
}
}
}

function evaluateJsonValueByPath(
jsonObject: any,
propParams: JsonPropertyMetadata
) {
if (propParams.paths)
return propParams.paths.map((path) => get(jsonObject, path))
if (propParams.pathAlternatives)
return propParams.pathAlternatives
.map((path) => get(jsonObject, path))
.find((value) => value != null)
return get(jsonObject, propParams.path)
}