Skip to content

Commit 1775a3c

Browse files
author
James Bodkin
committed
Add Jackson module to serialize/deserialize ArgumentValue
Signed-off-by: James Bodkin <[email protected]>
1 parent 75e7060 commit 1775a3c

File tree

8 files changed

+437
-0
lines changed

8 files changed

+437
-0
lines changed

spring-graphql-docs/modules/ROOT/pages/controllers.adoc

+19
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,25 @@ For example:
419419
method parameter, either initialized via a constructor argument or via a setter, including
420420
as a field of an object nested at any level below the top level object.
421421

422+
If you want to use `ArgumentValue` from a client or test, you can register the
423+
`ArgumentValueModule` in Jackson which can serialize/deserialize the value depending on
424+
the state.
425+
426+
For example:
427+
428+
[source,java,indent=0,subs="verbatim,quotes"]
429+
----
430+
@Configuration
431+
public class ArgumentValueConfiguration {
432+
433+
@Bean
434+
public ArgumentValueModule argumentValueModule() {
435+
return new ArgumentValueModule();
436+
}
437+
438+
}
439+
----
440+
422441

423442
[[controllers.schema-mapping.arguments]]
424443
=== `@Arguments`
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data.jackson;
18+
19+
import com.fasterxml.jackson.databind.DeserializationContext;
20+
import com.fasterxml.jackson.databind.JavaType;
21+
import com.fasterxml.jackson.databind.JsonDeserializer;
22+
import com.fasterxml.jackson.databind.JsonMappingException;
23+
import com.fasterxml.jackson.databind.deser.ValueInstantiator;
24+
import com.fasterxml.jackson.databind.deser.std.ReferenceTypeDeserializer;
25+
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
26+
import org.springframework.graphql.data.ArgumentValue;
27+
28+
import java.io.Serial;
29+
import java.io.Serializable;
30+
31+
public class ArgumentValueDeserializer extends ReferenceTypeDeserializer<ArgumentValue<?>> {
32+
33+
@Serial
34+
private static final long serialVersionUID = 1L;
35+
36+
public ArgumentValueDeserializer(final JavaType fullType, final ValueInstantiator vi,
37+
final TypeDeserializer typeDeser, final JsonDeserializer<?> deser) {
38+
39+
super(fullType, vi, typeDeser, deser);
40+
}
41+
42+
@Override
43+
protected ReferenceTypeDeserializer<ArgumentValue<?>> withResolved(final TypeDeserializer typeDeser,
44+
final JsonDeserializer<?> valueDeser) {
45+
46+
return new ArgumentValueDeserializer(_fullType, _valueInstantiator, typeDeser, valueDeser);
47+
}
48+
49+
@Override
50+
public ArgumentValue<? extends Serializable> getNullValue(final DeserializationContext ctxt) throws JsonMappingException {
51+
return ArgumentValue.ofNullable((Serializable) _valueDeserializer.getNullValue(ctxt));
52+
}
53+
54+
@Override
55+
public Object getEmptyValue(final DeserializationContext ctxt) throws JsonMappingException {
56+
return getNullValue(ctxt);
57+
}
58+
59+
@Override
60+
public Object getAbsentValue(final DeserializationContext ctxt) {
61+
return ArgumentValue.omitted();
62+
}
63+
64+
@Override
65+
public ArgumentValue<?> referenceValue(final Object contents) {
66+
return ArgumentValue.ofNullable((Serializable) contents);
67+
}
68+
69+
@Override
70+
public Object getReferenced(final ArgumentValue<?> value) {
71+
return value.value();
72+
}
73+
74+
@Override
75+
public ArgumentValue<?> updateReference(final ArgumentValue<?> value, final Object contents) {
76+
return ArgumentValue.ofNullable((Serializable) contents);
77+
}
78+
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data.jackson;
18+
19+
import com.fasterxml.jackson.databind.BeanDescription;
20+
import com.fasterxml.jackson.databind.DeserializationConfig;
21+
import com.fasterxml.jackson.databind.JsonDeserializer;
22+
import com.fasterxml.jackson.databind.deser.Deserializers;
23+
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
24+
import com.fasterxml.jackson.databind.type.ReferenceType;
25+
import org.springframework.graphql.data.ArgumentValue;
26+
27+
public class ArgumentValueDeserializers extends Deserializers.Base {
28+
29+
@Override
30+
public JsonDeserializer<?> findReferenceDeserializer(final ReferenceType refType, final DeserializationConfig config,
31+
final BeanDescription beanDesc, final TypeDeserializer contentTypeDeserializer,
32+
final JsonDeserializer<?> contentDeserializer) {
33+
34+
if (refType.hasRawClass(ArgumentValue.class)) {
35+
return new ArgumentValueDeserializer(refType, null, contentTypeDeserializer, contentDeserializer);
36+
} else {
37+
return null;
38+
}
39+
}
40+
41+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data.jackson;
18+
19+
import com.fasterxml.jackson.annotation.JsonInclude;
20+
import com.fasterxml.jackson.core.Version;
21+
import com.fasterxml.jackson.databind.Module;
22+
import org.springframework.graphql.data.ArgumentValue;
23+
24+
public class ArgumentValueModule extends Module {
25+
26+
@Override
27+
public String getModuleName() {
28+
return ArgumentValueModule.class.getName();
29+
}
30+
31+
@Override
32+
public Version version() {
33+
return Version.unknownVersion();
34+
}
35+
36+
@Override
37+
public void setupModule(final SetupContext context) {
38+
context.addSerializers(new ArgumentValueSerializers());
39+
context.addDeserializers(new ArgumentValueDeserializers());
40+
context.addTypeModifier(new ArgumentValueTypeModifier());
41+
42+
context.configOverride(ArgumentValue.class)
43+
.setInclude(JsonInclude.Value.empty().withValueInclusion(JsonInclude.Include.NON_ABSENT));
44+
}
45+
46+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data.jackson;
18+
19+
import com.fasterxml.jackson.databind.BeanProperty;
20+
import com.fasterxml.jackson.databind.JsonSerializer;
21+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
22+
import com.fasterxml.jackson.databind.ser.std.ReferenceTypeSerializer;
23+
import com.fasterxml.jackson.databind.type.ReferenceType;
24+
import com.fasterxml.jackson.databind.util.NameTransformer;
25+
import org.springframework.graphql.data.ArgumentValue;
26+
27+
import java.io.Serial;
28+
29+
public class ArgumentValueSerializer extends ReferenceTypeSerializer<ArgumentValue<?>> {
30+
31+
@Serial
32+
private static final long serialVersionUID = 1L;
33+
34+
public ArgumentValueSerializer(final ReferenceType fullType, final boolean staticTyping,
35+
final TypeSerializer vts, final JsonSerializer<Object> ser) {
36+
37+
super(fullType, staticTyping, vts, ser);
38+
}
39+
40+
protected ArgumentValueSerializer(final ArgumentValueSerializer base, final BeanProperty property,
41+
final TypeSerializer vts, final JsonSerializer<?> valueSer,
42+
final NameTransformer unwrapper, final Object suppressableValue,
43+
final boolean suppressNulls) {
44+
45+
super(base, property, vts, valueSer, unwrapper, suppressableValue, suppressNulls);
46+
}
47+
48+
@Override
49+
protected ReferenceTypeSerializer<ArgumentValue<?>> withResolved(final BeanProperty prop, final TypeSerializer vts,
50+
final JsonSerializer<?> valueSer, final NameTransformer unwrapper) {
51+
52+
return new ArgumentValueSerializer(this, prop, vts, valueSer, unwrapper, _suppressableValue, _suppressNulls);
53+
}
54+
55+
@Override
56+
public ReferenceTypeSerializer<ArgumentValue<?>> withContentInclusion(final Object suppressableValue, final boolean suppressNulls) {
57+
return new ArgumentValueSerializer(this, _property, _valueTypeSerializer,
58+
_valueSerializer, _unwrapper, suppressableValue, suppressNulls);
59+
}
60+
61+
@Override
62+
protected boolean _isValuePresent(final ArgumentValue<?> value) {
63+
return !value.isOmitted();
64+
}
65+
66+
@Override
67+
protected Object _getReferenced(final ArgumentValue<?> value) {
68+
return value.value();
69+
}
70+
71+
@Override
72+
protected Object _getReferencedIfPresent(final ArgumentValue<?> value) {
73+
return value.value();
74+
}
75+
76+
77+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data.jackson;
18+
19+
import com.fasterxml.jackson.databind.BeanDescription;
20+
import com.fasterxml.jackson.databind.JsonSerializer;
21+
import com.fasterxml.jackson.databind.MapperFeature;
22+
import com.fasterxml.jackson.databind.SerializationConfig;
23+
import com.fasterxml.jackson.databind.jsontype.TypeSerializer;
24+
import com.fasterxml.jackson.databind.ser.Serializers;
25+
import com.fasterxml.jackson.databind.type.ReferenceType;
26+
import org.springframework.graphql.data.ArgumentValue;
27+
28+
public class ArgumentValueSerializers extends Serializers.Base {
29+
30+
public JsonSerializer<?> findReferenceSerializer(final SerializationConfig config, final ReferenceType refType,
31+
final BeanDescription beanDesc, final TypeSerializer contentTypeSerializer,
32+
final JsonSerializer<Object> contentValueSerializer) {
33+
34+
final var raw = refType.getRawClass();
35+
if (ArgumentValue.class.isAssignableFrom(raw)) {
36+
final var staticTyping = contentTypeSerializer == null && config.isEnabled(MapperFeature.USE_STATIC_TYPING);
37+
return new ArgumentValueSerializer(refType, staticTyping, contentTypeSerializer, contentValueSerializer);
38+
} else {
39+
return null;
40+
}
41+
}
42+
43+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2002-2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.data.jackson;
18+
19+
import com.fasterxml.jackson.databind.JavaType;
20+
import com.fasterxml.jackson.databind.type.ReferenceType;
21+
import com.fasterxml.jackson.databind.type.TypeBindings;
22+
import com.fasterxml.jackson.databind.type.TypeFactory;
23+
import com.fasterxml.jackson.databind.type.TypeModifier;
24+
import org.springframework.graphql.data.ArgumentValue;
25+
26+
import java.lang.reflect.Type;
27+
28+
public class ArgumentValueTypeModifier extends TypeModifier {
29+
30+
@Override
31+
public JavaType modifyType(final JavaType type, final Type jdkType, final TypeBindings context, final TypeFactory typeFactory) {
32+
final var raw = type.getRawClass();
33+
if (!type.isReferenceType() && !type.isContainerType() && raw == ArgumentValue.class) {
34+
final var refType = type.containedTypeOrUnknown(0);
35+
return ReferenceType.upgradeFrom(type, refType);
36+
} else {
37+
return type;
38+
}
39+
}
40+
41+
}

0 commit comments

Comments
 (0)