下面列出了怎么用com.fasterxml.jackson.annotation.JsonTypeInfo的API类实例代码及写法,或者点击链接到github查看源代码。
private Optional<InheritanceInfo> getInheritanceInfo(Class<?> clazz) {
if (clazz.getAnnotation(JsonSubTypes.class) != null) {
List<Annotation> annotations = unmodifiableList(asList(clazz.getAnnotations()));
JsonTypeInfo jsonTypeInfo = annotations.stream()
.filter(annotation -> annotation instanceof JsonTypeInfo)
.map(annotation -> (JsonTypeInfo) annotation)
.findFirst()
.orElse(null);
InheritanceInfo inheritanceInfo = new InheritanceInfo();
inheritanceInfo.setDiscriminatorFieldName(getDiscriminatorName(jsonTypeInfo));
inheritanceInfo.setDiscriminatorClassMap(scanJacksonInheritance(annotations));
return Optional.of(inheritanceInfo);
}
return Optional.empty();
}
/**
* Providing custom schema definition for field/method in case of a per-property override of the applicable subtypes or how they are serialized.
*
* @param scope targeted field or method
* @param context generation context
* @return applicable custom per-property override schema definition (may be {@code null})
*/
public CustomPropertyDefinition provideCustomPropertySchemaDefinition(MemberScope<?, ?> scope, SchemaGenerationContext context) {
JsonTypeInfo typeInfoAnnotation = scope.getAnnotationConsideringFieldAndGetter(JsonTypeInfo.class);
if (typeInfoAnnotation == null || scope.getType().getErasedType().getDeclaredAnnotation(JsonSubTypes.class) != null) {
return null;
}
ObjectNode attributes;
if (scope instanceof FieldScope) {
attributes = AttributeCollector.collectFieldAttributes((FieldScope) scope, context);
} else if (scope instanceof MethodScope) {
attributes = AttributeCollector.collectMethodAttributes((MethodScope) scope, context);
} else {
attributes = null;
}
ObjectNode definition = this.createSubtypeDefinition(scope.getType(), typeInfoAnnotation, attributes, context);
if (definition == null) {
return null;
}
return new CustomPropertyDefinition(definition, CustomDefinition.AttributeInclusion.NO);
}
/**
* The sub type names refer to the {@link JobType} enumeration. Defaults to null for unmapped job types.
*/
@JacksonXmlProperty
@JsonProperty
@Property( required = FALSE )
@JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "jobType", defaultImpl = java.lang.Void.class )
@JsonSubTypes( value = {
@JsonSubTypes.Type( value = AnalyticsJobParameters.class, name = "ANALYTICS_TABLE" ),
@JsonSubTypes.Type( value = ContinuousAnalyticsJobParameters.class, name = "CONTINUOUS_ANALYTICS_TABLE" ),
@JsonSubTypes.Type( value = MonitoringJobParameters.class, name = "MONITORING" ),
@JsonSubTypes.Type( value = PredictorJobParameters.class, name = "PREDICTOR" ),
@JsonSubTypes.Type( value = PushAnalysisJobParameters.class, name = "PUSH_ANALYSIS" ),
@JsonSubTypes.Type( value = SmsJobParameters.class, name = "SMS_SEND" ),
@JsonSubTypes.Type( value = MetadataSyncJobParameters.class, name = "META_DATA_SYNC" ),
@JsonSubTypes.Type( value = EventProgramsDataSynchronizationJobParameters.class, name = "EVENT_PROGRAMS_DATA_SYNC" ),
@JsonSubTypes.Type( value = TrackerProgramsDataSynchronizationJobParameters.class, name = "TRACKER_PROGRAMS_DATA_SYNC" ),
@JsonSubTypes.Type( value = DataSynchronizationJobParameters.class, name = "DATA_SYNC" )
} )
public JobParameters getJobParameters()
{
return jobParameters;
}
@Bean
public RedisSerializer<Object> redisSerializer() {
//创建JSON序列化器
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.configure(MapperFeature.USE_ANNOTATIONS, false);
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
//TODO: 此项必须配置,否则会报java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to XXX
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance ,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return jackson2JsonRedisSerializer;
}
@RequestMapping("/")
@ResponseBody
public String home(@RequestParam(value = "name", defaultValue = "guest", required = false) String name) throws IOException {
Random rand = new Random();
int id = rand.nextInt();
User webUser = new User(id, name);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(webUser);
oos.close();
String webUserOISB64 = Base64.getEncoder().encodeToString(baos.toByteArray());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
String webUserJackson = objectMapper.writeValueAsString(webUser);
String webUserJacksonB64 = Base64.getEncoder().encodeToString(webUserJackson.getBytes("utf-8"));
return String.format("<a href='/?name=test'>set your name</a></br><a href='ois?sess=%s'>look at yourself</a></br><a href='jackson?sess=%s'>look at yourself</a>", webUserOISB64, webUserJacksonB64);
}
private static void handleJsonSubTypes(Class<?> clazz, ComposedSchema schema, Map<String, Class<?>> referencedClasses) {
final JsonTypeInfo typeInfo = clazz.getAnnotation(JsonTypeInfo.class);
final JsonSubTypes subTypes = clazz.getAnnotation(JsonSubTypes.class);
if (typeInfo != null && subTypes != null) {
final Discriminator discriminator = new Discriminator().propertyName(typeInfo.property().equals("") ? typeInfo.use().getDefaultPropertyName() : typeInfo.property());
for (JsonSubTypes.Type type : subTypes.value()) {
final Schema<?> reference = createReference(type.value(), clazz, referencedClasses);
schema.addOneOfItem(reference);
if (StringUtils.isNotEmpty(type.name()) || typeInfo.use() == JsonTypeInfo.Id.CLASS) {
// TODO: 2019-06-24 fix this once mappings are correctly handled elsewhere
// discriminator.mapping(type.name(), reference.get$ref());
discriminator.mapping(typeInfo.use() == JsonTypeInfo.Id.CLASS ? type.value().getName() : type.name(), "#/components/schemas/" + type.value().getSimpleName());
}
}
schema.discriminator(discriminator);
}
}
@Override
public TypeSerializer buildTypeSerializer(SerializationConfig config,
JavaType baseType, Collection<NamedType> subtypes)
{
if (_idType == JsonTypeInfo.Id.NONE) { return null; }
// 03-Oct-2016, tatu: As per [databind#1395] better prevent use for primitives,
// regardless of setting
if (baseType.isPrimitive()) {
return null;
}
TypeIdResolver idRes = idResolver(config, baseType, subtypes, true, false);
switch (_includeAs) {
case WRAPPER_ARRAY:
return new AsArrayTypeSerializer(idRes, null);
case PROPERTY:
return new AsPropertyTypeSerializer(idRes, null, _typeProperty);
case WRAPPER_OBJECT:
return new AsWrapperTypeSerializer(idRes, null);
case EXTERNAL_PROPERTY:
return new AsExternalTypeSerializer(idRes, null, _typeProperty);
case EXISTING_PROPERTY:
// as per [#528]
return new AsExistingPropertyTypeSerializer(idRes, null, _typeProperty);
}
throw new IllegalStateException("Do not know how to construct standard type serializer for inclusion type: "+_includeAs);
}
@BeforeClass
public static void beforeClass() {
// demonstrate our ability to set advanced configuration on a mapper
ObjectMapper mapper = new ObjectMapper();
// in this case, we're saying wrap our serialization with the name of the pojo class
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_OBJECT);
// register a JacksonDatabindHandleFactory ready to marshall any City object to/from json
// this enables the writeAs method below
DatabaseClientFactory.getHandleRegistry().register(
JacksonDatabindHandle.newFactory(mapper, City.class)
);
// we cannot use the singleton DatabaseClient here because this test requires
// a DatabaseClient created after calling getHandleRegistry().register() with City.class
client = Common.newClient();
}
@JsonAlias({"load-balancer-type", "type"})
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.WRAPPER_OBJECT
)
@Override
public void setLoadBalancerType(LoadBalancerDefinition loadbalancer) {
super.setLoadBalancerType(loadbalancer);
}
private String getJsonType(Class<?> clazz, JsonTypeInfo typeInfo) {
String value;
JsonTypeInfo.Id use = typeInfo.use();
switch (use) {
case CLASS:
value = clazz.getName();
break;
case NAME: {
JsonSubTypes.Type needed = null;
JsonSubTypes subTypes = AnnotationUtils.findAnnotation(clazz, JsonSubTypes.class);
if(subTypes != null) {
for(JsonSubTypes.Type type: subTypes.value()) {
if(type.value().equals(clazz)) {
needed = type;
break;
}
}
}
if(needed == null) {
throw new IllegalArgumentException("On " + clazz + " can not find 'JsonSubTypes' record for current type.");
}
value = needed.name();
break;
}
default:
throw new IllegalArgumentException("On " + clazz + " find unexpected 'JsonTypeInfo.use' value: " + use);
}
return value;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public void setResults(List<HealthCheckResultData> results) {
this.results.clear();
if(results != null) {
this.results.addAll(results);
}
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "kdf")
@JsonSubTypes({
@JsonSubTypes.Type(value = Aes128CtrKdfParams.class, name = KeyStore.AES_128_CTR),
@JsonSubTypes.Type(value = ScryptKdfParams.class, name = KeyStore.SCRYPT)
})
// To support my Ether Wallet keys uncomment this annotation & comment out the above
// @JsonDeserialize(using = KdfParamsDeserialiser.class)
// Also add the following to the ObjectMapperFactory
// objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
public void setKdfparams(KdfParams kdfparams) {
this.kdfparams = kdfparams;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME)
@JsonSubTypes({
@Type(name = "I", value = Integer.class),
@Type(name = "O", value = Double.class)
})
// the annotation will be copied to a builder setter
public abstract @Nullable Object value();
public JacksonJsonSerializer() {
// mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
MAPPER.registerModule(
new SimpleModule().addSerializer(new JacksonJsonSerializer.NullValueSerializer((String) null)));
MAPPER.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "resourceType", defaultImpl=TaskQueryDto.class)
@JsonSubTypes(value = {
@JsonSubTypes.Type(value = TaskQueryDto.class, name = EntityTypes.TASK)})
public void setQuery(AbstractQueryDto<?> query) {
this.query = query;
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "kdf")
@JsonSubTypes({
@JsonSubTypes.Type(value = Aes128CtrKdfParams.class, name = Wallet.AES_128_CTR),
@JsonSubTypes.Type(value = ScryptKdfParams.class, name = Wallet.SCRYPT)
})
// To support my Ether Wallet keys uncomment this annotation & comment out the above
// @JsonDeserialize(using = KdfParamsDeserialiser.class)
// Also add the following to the ObjectMapperFactory
// objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
public void setKdfparams(KdfParams kdfparams) {
this.kdfparams = kdfparams;
}
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.EXTERNAL_PROPERTY,
property = "kdf")
@JsonSubTypes({
@JsonSubTypes.Type(value = Aes128CtrKdfParams.class, name = Wallet.AES_128_CTR),
@JsonSubTypes.Type(value = ScryptKdfParams.class, name = Wallet.SCRYPT)
})
// To support my Ether Wallet keys uncomment this annotation & comment out the above
// @JsonDeserialize(using = KdfParamsDeserialiser.class)
// Also add the following to the ObjectMapperFactory
// objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
public void setKdfparams(KdfParams kdfparams) {
this.kdfparams = kdfparams;
}
/**
* @param ctx Defines a kernal context to enable deserialization into the Ignite binary object.
*/
GridJettyObjectMapper(GridKernalContext ctx) {
super(null, new CustomSerializerProvider(), null);
setDateFormat(DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, Locale.US));
SimpleModule module = new SimpleModule();
module.addSerializer(Throwable.class, THROWABLE_SERIALIZER);
module.addSerializer(IgniteBiTuple.class, IGNITE_TUPLE_SERIALIZER);
module.addSerializer(IgniteUuid.class, IGNITE_UUID_SERIALIZER);
module.addSerializer(GridCacheSqlMetadata.class, IGNITE_SQL_METADATA_SERIALIZER);
module.addSerializer(GridCacheSqlIndexMetadata.class, IGNITE_SQL_INDEX_METADATA_SERIALIZER);
module.addSerializer(BinaryObjectImpl.class, IGNITE_BINARY_OBJECT_SERIALIZER);
// Standard serializer loses nanoseconds.
module.addSerializer(Timestamp.class, IGNITE_TIMESTAMP_SERIALIZER);
module.addDeserializer(Timestamp.class, IGNITE_TIMESTAMP_DESERIALIZER);
// Standard serializer may incorrectly apply timezone.
module.addSerializer(Date.class, IGNITE_SQLDATE_SERIALIZER);
module.addDeserializer(Date.class, IGNITE_SQLDATE_DESERIALIZER);
if (ctx != null) {
module.addDeserializer(BinaryObject.class, new IgniteBinaryObjectJsonDeserializer(ctx));
IgnitePredicate<String> clsFilter = ctx.marshallerContext().classNameFilter();
setDefaultTyping(new RestrictedTypeResolverBuilder(clsFilter).init(JsonTypeInfo.Id.CLASS, null));
}
configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
registerModule(module);
}
protected void initTypeInclusion(ObjectMapper mapObjectMapper) {
TypeResolverBuilder<?> mapTyper = new DefaultTypeResolverBuilder(DefaultTyping.NON_FINAL) {
public boolean useForType(JavaType t) {
switch (_appliesFor) {
case NON_CONCRETE_AND_ARRAYS:
while (t.isArrayType()) {
t = t.getContentType();
}
// fall through
case OBJECT_AND_NON_CONCRETE:
return (t.getRawClass() == Object.class) || !t.isConcrete();
case NON_FINAL:
while (t.isArrayType()) {
t = t.getContentType();
}
// to fix problem with wrong long to int conversion
if (t.getRawClass() == Long.class) {
return true;
}
if (t.getRawClass() == XMLGregorianCalendar.class) {
return false;
}
return !t.isFinal(); // includes Object.class
default:
// case JAVA_LANG_OBJECT:
return t.getRawClass() == Object.class;
}
}
};
mapTyper.init(JsonTypeInfo.Id.CLASS, null);
mapTyper.inclusion(JsonTypeInfo.As.PROPERTY);
mapObjectMapper.setDefaultTyping(mapTyper);
}
@Override
public void emitElements(Writer writer, Settings settings, boolean exportKeyword, TsModel model) {
for (TsBeanModel tsBean : model.getBeans()) {
final Class<?> beanClass = tsBean.getOrigin();
if (beanClass != null) {
final JsonSubTypes jsonSubTypes = beanClass.getAnnotation(JsonSubTypes.class);
final JsonTypeInfo jsonTypeInfo = beanClass.getAnnotation(JsonTypeInfo.class);
if (jsonSubTypes != null && jsonTypeInfo != null && jsonTypeInfo.include() == JsonTypeInfo.As.PROPERTY) {
final String propertyName = jsonTypeInfo.property();
for (JsonSubTypes.Type subType : jsonSubTypes.value()) {
String propertyValue = null;
if (jsonTypeInfo.use() == JsonTypeInfo.Id.NAME) {
if (subType.name().equals("")) {
final JsonTypeName jsonTypeName = subType.value().getAnnotation(JsonTypeName.class);
if (jsonTypeName != null) {
propertyValue = jsonTypeName.value();
}
} else {
propertyValue = subType.name();
}
}
if (propertyValue != null) {
final String baseTypeName = tsBean.getName().getSimpleName();
final String subTypeName = findTypeName(subType.value(), model);
if (baseTypeName != null && subTypeName != null) {
writer.writeIndentedLine("");
emitTypeGuard(writer, settings, exportKeyword, baseTypeName, subTypeName, propertyName, propertyValue);
}
}
}
}
}
}
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public ApplicationInfo getApplicationInfo() {
return applicationInfo;
}
@Override
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public ObjectIdentity getObjectIdentity() {
return this.objectIdentity;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@Override
public Object getDetails() {
return details;
}
@Override
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "topic", defaultImpl = DmfActionRequest.class)
@JsonSubTypes({ @Type(value = DmfDownloadAndUpdateRequest.class, name = "DOWNLOAD"),
@Type(value = DmfDownloadAndUpdateRequest.class, name = "DOWNLOAD_AND_INSTALL") })
public void setAction(final DmfActionRequest action) {
this.action = action;
}
@Override
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
public Set<GrantedAuthority> getAuthorities() {
return authorities;
}
/**
* Create the custom schema definition for the given subtype, considering the {@link JsonTypeInfo#include()} setting.
*
* @param javaType targeted subtype
* @param typeInfoAnnotation annotation for looking up the type identifier and determining the kind of inclusion/serialization
* @param attributesToInclude optional: additional attributes to include on the actual/contained schema definition
* @param context generation context
* @return created custom definition (or {@code null} if no supported subtype resolution scenario could be detected
*/
private ObjectNode createSubtypeDefinition(ResolvedType javaType, JsonTypeInfo typeInfoAnnotation, ObjectNode attributesToInclude,
SchemaGenerationContext context) {
final String typeIdentifier = this.getTypeIdentifier(javaType, typeInfoAnnotation);
if (typeIdentifier == null) {
return null;
}
final ObjectNode definition = context.getGeneratorConfig().createObjectNode();
switch (typeInfoAnnotation.include()) {
case WRAPPER_ARRAY:
definition.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_ARRAY));
ArrayNode itemsArray = definition.withArray(context.getKeyword(SchemaKeyword.TAG_ITEMS));
itemsArray.addObject()
.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_STRING))
.put(context.getKeyword(SchemaKeyword.TAG_CONST), typeIdentifier);
if (attributesToInclude == null || attributesToInclude.isEmpty()) {
itemsArray.add(context.createStandardDefinitionReference(javaType, this));
} else {
itemsArray.addObject()
.withArray(context.getKeyword(SchemaKeyword.TAG_ALLOF))
.add(context.createStandardDefinitionReference(javaType, this))
.add(attributesToInclude);
}
break;
case WRAPPER_OBJECT:
definition.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_OBJECT));
ObjectNode propertiesNode = definition.with(context.getKeyword(SchemaKeyword.TAG_PROPERTIES));
if (attributesToInclude == null || attributesToInclude.isEmpty()) {
propertiesNode.set(typeIdentifier, context.createStandardDefinitionReference(javaType, this));
} else {
propertiesNode.with(typeIdentifier)
.withArray(context.getKeyword(SchemaKeyword.TAG_ALLOF))
.add(context.createStandardDefinitionReference(javaType, this))
.add(attributesToInclude);
}
break;
case PROPERTY:
case EXISTING_PROPERTY:
final String propertyName = Optional.ofNullable(typeInfoAnnotation.property())
.filter(name -> !name.isEmpty())
.orElseGet(() -> typeInfoAnnotation.use().getDefaultPropertyName());
ObjectNode additionalPart = definition.withArray(context.getKeyword(SchemaKeyword.TAG_ALLOF))
.add(context.createStandardDefinitionReference(javaType, this))
.addObject();
if (attributesToInclude != null && !attributesToInclude.isEmpty()) {
additionalPart.setAll(attributesToInclude);
}
additionalPart.put(context.getKeyword(SchemaKeyword.TAG_TYPE), context.getKeyword(SchemaKeyword.TAG_TYPE_OBJECT))
.with(context.getKeyword(SchemaKeyword.TAG_PROPERTIES))
.with(propertyName)
.put(context.getKeyword(SchemaKeyword.TAG_CONST), typeIdentifier);
break;
default:
return null;
}
return definition;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, defaultImpl = Object.class)
public T getPayload()
{
return payload;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.WRAPPER_OBJECT)
public TestSuperClassWithNameProperty getSupertypeWithAnnotationOnFieldAndGetter() {
return this.supertypeWithAnnotationOnFieldAndGetter;
}
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS)
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}