使用Jackson批注的JSON模式中的自定义属性关键字

时间:2019-09-30 12:06:42

标签: java json jackson jsonschema

我想创建在使用Jackson生成的JSON模式中预设的自定义属性关键字。这将类似于JsonPropertyDescription批注所做的事情,但用于自定义批注和关键字。例如,我希望能够使用自定义JsonPropertyLabel注释对属性进行注释,该注释将在属性描述中添加“ label”关键字。

我确实使用这样的自定义JsonSchema和JsonSchemaFactory做了类似的事情:

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.module.jsonSchema.JsonSchema;
import com.fasterxml.jackson.module.jsonSchema.customProperties.ValidationSchemaFactoryWrapper;
import com.fasterxml.jackson.module.jsonSchema.factories.FormatVisitorFactory;
import com.fasterxml.jackson.module.jsonSchema.factories.JsonSchemaFactory;
import com.fasterxml.jackson.module.jsonSchema.factories.SchemaFactoryWrapper;
import com.fasterxml.jackson.module.jsonSchema.factories.VisitorContext;
import com.fasterxml.jackson.module.jsonSchema.factories.WrapperFactory;
import com.fasterxml.jackson.module.jsonSchema.types.ObjectSchema;
import com.fasterxml.jackson.annotation.JacksonAnnotation;
import com.fasterxml.jackson.module.jsonSchema.validation.AnnotationConstraintResolver;


public class SchemaUtils {

    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @JacksonAnnotation
    public @interface JsonPropertyLabel {
        String value();
    }

    public static String getPrettyClassSchema(Class type) throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(ConfigurationUtils.getJsonSchema(type, objectMapper));
    }

    static JsonSchema getJsonSchema(Class type, ObjectMapper objectMapper) throws JsonMappingException {
        SchemaFactoryWrapper schemaFactoryWrapper = new CustomJsonSchemaFactoryWrapper();
        objectMapper.acceptJsonFormatVisitor(objectMapper.constructType(type), schemaFactoryWrapper); 
        return schemaFactoryWrapper.finalSchema();
    }

    static class CustomJsonSchemaFactoryWrapper extends ValidationSchemaFactoryWrapper {
    private static class SchemaFactoryWrapperFactory extends WrapperFactory {
      private SchemaFactoryWrapperFactory() {
      }

      public SchemaFactoryWrapper getWrapper(SerializerProvider p) {
        return this.getWrapper(p, null);
      }

      public SchemaFactoryWrapper getWrapper(SerializerProvider p, VisitorContext rvc) {
        SchemaFactoryWrapper wrapper = new CustomJsonSchemaFactoryWrapper();
        wrapper.setProvider(p);
        if(rvc != null) {
          wrapper.setVisitorContext(rvc);
        }
        return wrapper;
      }
    }

    public CustomJsonSchemaFactoryWrapper() {
      super(new AnnotationConstraintResolver());
      schemaProvider = new CustomJsonSchemaFactory();
      visitorFactory = new FormatVisitorFactory(new SchemaFactoryWrapperFactory());
    }

    static class CustomJsonSchemaFactory extends JsonSchemaFactory {
      @Override
      public ObjectSchema objectSchema() {
        return new CustomJsonSchema();
      }

      static class CustomJsonSchema extends ObjectSchema {
        @JsonProperty private String label;

        @Override
        public void enrichWithBeanProperty(BeanProperty beanProperty) {
          super.enrichWithBeanProperty(beanProperty);
          JsonPropertyLabel labelAnnotation = beanProperty.getAnnotation(JsonPropertyLabel.class);
          if (labelAnnotation != null) {
            this.label = labelAnnotation.value();
          }
        }
      }
    }
  }
}

但是,在以下类上尝试此代码时:

public class POJOExample {
  @JsonPropertyDescription("first property description")
  @JsonPropertyLabel("first  property label")
  public PropertyExample first;

  @JsonPropertyDescription("second property description")
  @JsonPropertyLabel("second property label")
  public PropertyExample second;

  public static class PropertyExample {
    public String value;
  }
}

用于此目的的JSON模式如下:

{
  "type" : "object",
  "id" : "urn:jsonschema:test:POJOExample",
  "properties" : {
    "first" : {
      "type" : "object",
      "id" : "urn:jsonschema:test:POJOExample:PropertyExample",
      "description" : "first property description",
      "properties" : {
        "value" : {
          "type" : "string"
        }
      },
      "label" : "first  property label"
    },
    "second" : {
      "type" : "object",
      "$ref" : "urn:jsonschema:test:POJOExample:PropertyExample",
      "description" : "second property description"
    }
  }
}

如您所见,“第一个”同时具有“描述”和“标签”,而芽“第二个”仅具有“描述”。我想此实现将“标签”捆绑为可通过引用获得的类型功能。我将如何使“标签”表现得像“描述”一样,并在“第二”属性上也有它?

此外,如果我能够提前在运行时不知道关键字字符串值的用例中动态执行此操作,那将是最佳选择。例如,具有如下注释的JsonPropertyKeyword:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@JacksonAnnotation
public @interface JsonPropertyKeyword {
  String keyword();
  String value();
}

这样,我可以使用@JsonPropertyKeyword(keyword="description", value="some description")注释属性,并获得与@JsonPropertyDescription("some description")相同的效果。这可能吗?

0 个答案:

没有答案