Repository: swagger-api/swagger-core (language: java)

Issue:
@JsonView ignored for subclasses
I am having a parent class with subclasses. I am using different `@JsonView` annotations where the classes are used for request bodies and response bodies.

When generating a schema from the parent class for a given `@JsonView`, the schema generated for the child class contains an incorrect selection of the classes' fields.

```java
public class Demo {

	public interface Input {}

	public interface Output {}

	@JsonTypeInfo(use = NAME)
	@JsonSubTypes({
		@JsonSubTypes.Type(value = A1.class),
	})
	public static abstract class A {
		@JsonView(Input.class)
		public String a_in;
		@JsonView(Output.class)
		public String a_out;
	}

	public static class A1 extends A {
		@JsonView(Input.class)
		public String a1_in;
		@JsonView(Output.class)
		public String a1_out;
	}

	private static final JsonView VIEW_OUTPUT = new JsonView() {
		public Class<? extends Annotation> annotationType() {
			return JsonView.class;
		}
		public Class<?>[] value() {
			return new Class[] {Output.class};
		}
	};

	public static void main(String[] args) {
		ResolvedSchema resolvedSchema = ModelConverters.getInstance()
			.resolveAsResolvedSchema(
				new AnnotatedType(A.class).resolveAsRef(true)
					.jsonViewAnnotation(VIEW_OUTPUT));
		resolvedSchema.referencedSchemas.forEach((name, schema) -> dumpSchema(schema, ""));
	}

	private static void dumpSchema(Schema<?> schema, String indent) {
		if (schema.get$ref() != null) {
			System.out.println(indent + "$ref: " + schema.get$ref());
		}
		if (schema.getName() != null) {
			System.out.println(indent + "Schema: " + schema.getName());
		}
		if (schema.getType() != null) {
			System.out.println(indent + "Type: " + schema.getType());
		}
		if (schema.getAllOf() != null) {
			System.out.println(indent + "All of:");
			schema.getAllOf().forEach((allOfSchema) -> dumpSchema(allOfSchema, indent + "  "));
		}
		if (schema.getProperties() != null) {
			System.out.println(indent + "Properties:");
			schema.getProperties().forEach((propName, propSchema) -> {
				System.out.println(indent + propName);
				dumpSchema(propSchema, indent + "  ");
			});
		}
	}
}
```

This is the actual output:

```
Schema: A1
Type: object
All of:
  $ref: #/components/schemas/A_Output
  Type: object
  Properties:
  a_in
    Schema: a_in
    Type: string
  a1_in
    Schema: a1_in
    Type: string
  a1_out
    Schema: a1_out
    Type: string
Schema: A_Output
Type: object
Properties:
a_out
  Schema: a_out
  Type: string
```

What I would expect instead:

```diff
- Schema: A1
+ Schema: A1_Output
Type: object
All of:
  $ref: #/components/schemas/A_Output
  Type: object
  Properties:
-  a_in
-    Schema: a_in
-    Type: string
-  a1_in
-    Schema: a1_in
-    Type: string
  a1_out
    Schema: a1_out
    Type: string
Schema: A_Output
Type: object
Properties:
a_out
  Schema: a_out
  Type: string
```

[I have pushed a minimal reproducible example to GitHub.](https://github.com/devopsix/swagger-core-jsonview-subtypes)

swagger-core version: ~2.2.2~ 2.2.4
jackson-core version: 2.13.3
Java, OpenJDK 18.0.2.1

@JsonView ignored for subclasses
I am having a parent class with subclasses. I am using different `@JsonView` annotations where the classes are used for request bodies and response bodies.

When generating a schema from the parent class for a given `@JsonView`, the schema generated for the child class contains an incorrect selection of the classes' fields.

```java
public class Demo {

	public interface Input {}

	public interface Output {}

	@JsonTypeInfo(use = NAME)
	@JsonSubTypes({
		@JsonSubTypes.Type(value = A1.class),
	})
	public static abstract class A {
		@JsonView(Input.class)
		public String a_in;
		@JsonView(Output.class)
		public String a_out;
	}

	public static class A1 extends A {
		@JsonView(Input.class)
		public String a1_in;
		@JsonView(Output.class)
		public String a1_out;
	}

	private static final JsonView VIEW_OUTPUT = new JsonView() {
		public Class<? extends Annotation> annotationType() {
			return JsonView.class;
		}
		public Class<?>[] value() {
			return new Class[] {Output.class};
		}
	};

	public static void main(String[] args) {
		ResolvedSchema resolvedSchema = ModelConverters.getInstance()
			.resolveAsResolvedSchema(
				new AnnotatedType(A.class).resolveAsRef(true)
					.jsonViewAnnotation(VIEW_OUTPUT));
		resolvedSchema.referencedSchemas.forEach((name, schema) -> dumpSchema(schema, ""));
	}

	private static void dumpSchema(Schema<?> schema, String indent) {
		if (schema.get$ref() != null) {
			System.out.println(indent + "$ref: " + schema.get$ref());
		}
		if (schema.getName() != null) {
			System.out.println(indent + "Schema: " + schema.getName());
		}
		if (schema.getType() != null) {
			System.out.println(indent + "Type: " + schema.getType());
		}
		if (schema.getAllOf() != null) {
			System.out.println(indent + "All of:");
			schema.getAllOf().forEach((allOfSchema) -> dumpSchema(allOfSchema, indent + "  "));
		}
		if (schema.getProperties() != null) {
			System.out.println(indent + "Properties:");
			schema.getProperties().forEach((propName, propSchema) -> {
				System.out.println(indent + propName);
				dumpSchema(propSchema, indent + "  ");
			});
		}
	}
}
```

This is the actual output:

```
Schema: A1
Type: object
All of:
  $ref: #/components/schemas/A_Output
  Type: object
  Properties:
  a_in
    Schema: a_in
    Type: string
  a1_in
    Schema: a1_in
    Type: string
  a1_out
    Schema: a1_out
    Type: string
Schema: A_Output
Type: object
Properties:
a_out
  Schema: a_out
  Type: string
```

What I would expect instead:

```diff
- Schema: A1
+ Schema: A1_Output
Type: object
All of:
  $ref: #/components/schemas/A_Output
  Type: object
  Properties:
-  a_in
-    Schema: a_in
-    Type: string
-  a1_in
-    Schema: a1_in
-    Type: string
  a1_out
    Schema: a1_out
    Type: string
Schema: A_Output
Type: object
Properties:
a_out
  Schema: a_out
  Type: string
```

[I have pushed a minimal reproducible example to GitHub.](https://github.com/devopsix/swagger-core-jsonview-subtypes)

swagger-core version: ~2.2.2~ 2.2.4
jackson-core version: 2.13.3
Java, OpenJDK 18.0.2.1



Discussion / hints:

Fix patch:
diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java
index 1a43e1fcd2..cfdcf8cbd8 100644
--- a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java
+++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java
@@ -742,7 +742,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context
          * This must be done after model.setProperties so that the model's set
          * of properties is available to filter from any subtypes
          **/
-        if (!resolveSubtypes(model, beanDesc, context)) {
+        if (!resolveSubtypes(model, beanDesc, context, annotatedType.getJsonViewAnnotation())) {
             model.setDiscriminator(null);
         }
 
@@ -1370,7 +1370,7 @@ protected void applyBeanValidatorAnnotations(Schema property, Annotation[] annot
         }
     }
 
-    private boolean resolveSubtypes(Schema model, BeanDescription bean, ModelConverterContext context) {
+    private boolean resolveSubtypes(Schema model, BeanDescription bean, ModelConverterContext context, JsonView jsonViewAnnotation) {
         final List<NamedType> types = _intr.findSubtypes(bean.getClassInfo());
         if (types == null) {
             return false;
@@ -1398,7 +1398,8 @@ private boolean resolveSubtypes(Schema model, BeanDescription bean, ModelConvert
                 continue;
             }
 
-            final Schema subtypeModel = context.resolve(new AnnotatedType().type(subtypeType));
+            final Schema subtypeModel = context.resolve(new AnnotatedType().type(subtypeType)
+                .jsonViewAnnotation(jsonViewAnnotation));
 
             if (    StringUtils.isBlank(subtypeModel.getName()) ||
                     subtypeModel.getName().equals(model.getName())) {


Test patch:
diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4239Test.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4239Test.java
new file mode 100644
index 0000000000..f192eb99d9
--- /dev/null
+++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4239Test.java
@@ -0,0 +1,75 @@
+package io.swagger.v3.core.resolving;
+
+import com.fasterxml.jackson.annotation.JsonSubTypes;
+import com.fasterxml.jackson.annotation.JsonTypeInfo;
+import com.fasterxml.jackson.annotation.JsonView;
+import io.swagger.v3.core.converter.AnnotatedType;
+import io.swagger.v3.core.converter.ModelConverterContextImpl;
+import io.swagger.v3.core.jackson.ModelResolver;
+import io.swagger.v3.core.matchers.SerializationMatchers;
+import org.testng.annotations.Test;
+
+import java.lang.annotation.Annotation;
+
+import static com.fasterxml.jackson.annotation.JsonTypeInfo.Id.NAME;
+
+public class Ticket4239Test extends SwaggerTestBase {
+
+    public interface Input {}
+
+    public interface Output {}
+
+    @JsonTypeInfo(use = NAME)
+    @JsonSubTypes({
+        @JsonSubTypes.Type(value = A1.class),
+    })
+    public static abstract class A {
+        @JsonView(Input.class)
+        public String a_in;
+        @JsonView(Output.class)
+        public String a_out;
+    }
+
+    public static class A1 extends A {
+        @JsonView(Input.class)
+        public String a1_in;
+        @JsonView(Output.class)
+        public String a1_out;
+    }
+
+    private static final JsonView VIEW_OUTPUT = new JsonView() {
+        public Class<? extends Annotation> annotationType() {
+            return JsonView.class;
+        }
+        public Class<?>[] value() {
+            return new Class[] {Output.class};
+        }
+    };
+
+    @Test
+    public void testJsonValueSchemaAnnotation() {
+
+        final ModelResolver modelResolver = new ModelResolver(mapper());
+
+        ModelConverterContextImpl context = new ModelConverterContextImpl(modelResolver);
+
+        AnnotatedType type = new AnnotatedType(Ticket4239Test.A.class).jsonViewAnnotation(VIEW_OUTPUT);
+
+        context.resolve(type);
+
+        SerializationMatchers.assertEqualsToYaml(context.getDefinedModels(), "A1_Output:\n" +
+            "  type: object\n" +
+            "  allOf:\n" +
+            "  - $ref: '#/components/schemas/A_Output'\n" +
+            "  - type: object\n" +
+            "    properties:\n" +
+            "      a1_out:\n" +
+            "        type: string\n" +
+            "A_Output:\n" +
+            "  type: object\n" +
+            "  properties:\n" +
+            "    a_out:\n" +
+            "      type: string\n");
+
+    }
+}