Forum Discussion

mehdisinger's avatar
4 years ago
Solved

Missing Json root element

Hi all,

 

We've set up Swagger UI for a while now (version 1.5.10) on our project but we are trying to find out wether it's possible to integrate the Json root element in the example value.

I see that this problem occurs also in your demo page https://petstore.swagger.io/?_ga=2.186999790.790751393.1601300889-613925661.1599659287

Example:

for the Pet model you display the following Json 

{
  "id": 0,
  "category": {
    "id": 0,
    "name": "string"
  },
  "name": "doggie",
  "photoUrls": [
    "string"
  ],
  "tags": [
    {
      "id": 0,
      "name": "string"
    }
  ],
  "status": "available"
}

Where I'm expecting to see:

 

{
  "Pet": {
    "id": 0,
    "category": {
      "id": 0,
      "name": "string"
    },
    "name": "doggie",
    "photoUrls": [
      "string"
    ],
    "tags": [
      {
        "id": 0,
        "name": "string"
      }
    ],
    "status": "available"
  }
}

 

I tried to add @JsonRootName annotation on my entities and set up WRAP_ROOT_VALUE/UNWRAP_ROOT_VALUE on  the Json serializer but I still don't get the expected result.

 

Thank you very much for your help !

 

Mehdi

 

  • I am not sure I fully understand goals and scenarios - also please note that example support and in general customization and extensibility are more advanced in Swagger Core v2 (https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Getting-started, supporting OpenAPI 3.0)  - however the example content is not dependent on any serialization preference on the server side, as it is dynamically built by swagger-ui (if an `example` field doesn't exist at Pet level) out of the defined schema.

     

    The schema resolved by swagger-core from Pet Pojo is also not dependent on whatever Jackson mapper serialization options of the Pojo itself (there can be many mapper, each applying or not WRAP_ROOT_VALUE, e.g the one used by the REST framework of choice, the one in use by swagger-core, any other..).

     

    It analyze the properties/members of the Pojo  and build a `Model` of it. This model (e.g. a `ModelImpl` object) is then serialized to JSON/YAML along with the whole resolved `Swagger` object to output the serialized resolved Swagger definition. 

     

    If the expected JSON accepted (or returned) by your endpoints includes the`Pet` as a property within a "wrapper" (as with Jackson WRAP_ROOT_VALUE) this would need to be defined in the model used, you could for example define a wrapper class and add that as type of the ApiParam or ApiImplicitParam annotation, e.g.

     

    public class PetWrapper{
    public Pet pet;
    }

     

    As mentioned above, a slightly more complicated alternative is providing an `example` value to the model, to obtain something like:

     

      Pet:
        type: "object"
        example: 
          pet:
            id: 0
            name: "mypet"
        properties:
          id:
            type: "integer"
            format: "int64"
          name:
            type: "string"
    

     

    unfortunately there is no annotation in Swagger Core v1 allowing to define the example for root models, but you can provide your own along with a custom ModelResolver, e.g.:

     

        class CustomConverter extends ModelResolver {
    
    
            public CustomConverter(ObjectMapper mapper) {
                super(mapper);        }
                
            @Override
            public Model resolve(JavaType type, ModelConverterContext context, Iterator<ModelConverter> next) {
                Model model = super.resolve(type, context, next);
                BeanDescription beanDesc = _mapper.getSerializationConfig().introspect(type);
                final ExampleAnnotation ann = beanDesc.getClassAnnotations().get(ExampleAnnotation.class);
                if (ann != null && !StringUtils.isBlank(ann.value())) {
                    try {
                        model.setExample(Json.mapper().readTree(ann.value()));
                    } catch (JsonProcessingException e) {
                        e.printStackTrace();
                        return model;
                    }
                }
                return model;
            }
        }

     

    @Target({ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    @Inherited
    public @interface ExampleAnnotation {
        String value() default "";
    }

     

    configuring it via service loader or in bootstrap code:

    ModelConverters.getInstance().addConverter(new CustomConverter());

     

    you would then be able to define the example for your pojo as you like:

    @ExampleAnnotation("{\"Pet\": {\"id\" : 0, \"name\": "...."}}")
    public class Pet {
        private long id;
        private Category category;
    ...
    ...

     

     

     

     

     

     

     

3 Replies

  • pica25's avatar
    pica25
    New Contributor

    I'm also having the same issues. Is there a way to solve this ?

    • pica25's avatar
      pica25
      New Contributor

      We are thinking to move away from Swagger if we cannot get an answer to this basic request. Can someone help ?

      • frantuma's avatar
        frantuma
        Staff

        I am not sure I fully understand goals and scenarios - also please note that example support and in general customization and extensibility are more advanced in Swagger Core v2 (https://github.com/swagger-api/swagger-core/wiki/Swagger-2.X---Getting-started, supporting OpenAPI 3.0)  - however the example content is not dependent on any serialization preference on the server side, as it is dynamically built by swagger-ui (if an `example` field doesn't exist at Pet level) out of the defined schema.

         

        The schema resolved by swagger-core from Pet Pojo is also not dependent on whatever Jackson mapper serialization options of the Pojo itself (there can be many mapper, each applying or not WRAP_ROOT_VALUE, e.g the one used by the REST framework of choice, the one in use by swagger-core, any other..).

         

        It analyze the properties/members of the Pojo  and build a `Model` of it. This model (e.g. a `ModelImpl` object) is then serialized to JSON/YAML along with the whole resolved `Swagger` object to output the serialized resolved Swagger definition. 

         

        If the expected JSON accepted (or returned) by your endpoints includes the`Pet` as a property within a "wrapper" (as with Jackson WRAP_ROOT_VALUE) this would need to be defined in the model used, you could for example define a wrapper class and add that as type of the ApiParam or ApiImplicitParam annotation, e.g.

         

        public class PetWrapper{
        public Pet pet;
        }

         

        As mentioned above, a slightly more complicated alternative is providing an `example` value to the model, to obtain something like:

         

          Pet:
            type: "object"
            example: 
              pet:
                id: 0
                name: "mypet"
            properties:
              id:
                type: "integer"
                format: "int64"
              name:
                type: "string"
        

         

        unfortunately there is no annotation in Swagger Core v1 allowing to define the example for root models, but you can provide your own along with a custom ModelResolver, e.g.:

         

            class CustomConverter extends ModelResolver {
        
        
                public CustomConverter(ObjectMapper mapper) {
                    super(mapper);        }
                    
                @Override
                public Model resolve(JavaType type, ModelConverterContext context, Iterator<ModelConverter> next) {
                    Model model = super.resolve(type, context, next);
                    BeanDescription beanDesc = _mapper.getSerializationConfig().introspect(type);
                    final ExampleAnnotation ann = beanDesc.getClassAnnotations().get(ExampleAnnotation.class);
                    if (ann != null && !StringUtils.isBlank(ann.value())) {
                        try {
                            model.setExample(Json.mapper().readTree(ann.value()));
                        } catch (JsonProcessingException e) {
                            e.printStackTrace();
                            return model;
                        }
                    }
                    return model;
                }
            }

         

        @Target({ElementType.TYPE})
        @Retention(RetentionPolicy.RUNTIME)
        @Inherited
        public @interface ExampleAnnotation {
            String value() default "";
        }

         

        configuring it via service loader or in bootstrap code:

        ModelConverters.getInstance().addConverter(new CustomConverter());

         

        you would then be able to define the example for your pojo as you like:

        @ExampleAnnotation("{\"Pet\": {\"id\" : 0, \"name\": "...."}}")
        public class Pet {
            private long id;
            private Category category;
        ...
        ...