diff --git a/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolver.java b/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolver.java index 73bbbd123..4521da818 100644 --- a/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolver.java +++ b/core/src/main/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolver.java @@ -76,6 +76,8 @@ public class TypeResolver { private boolean exposed = false; private boolean readOnly = false; private boolean writeOnly = false; + private MethodInfo ignoredReadMethod; + private MethodInfo ignoredWriteMethod; private final List constraintTargets = new ArrayList<>(); private String propertyNamePrefix; private String propertyNameSuffix; @@ -372,7 +374,17 @@ public Type resolveType() { public boolean isIgnored() { return ignored || (readOnly && readMethod == null && field == null) - || (writeOnly && writeMethod == null && field == null); + || (writeOnly && writeMethod == null && field == null) + || (ignoredReadMethod != null && readMethod == ignoredReadMethod && writeMethod == null + && !isFieldExplicitlyVisible()) + || (ignoredWriteMethod != null && writeMethod == ignoredWriteMethod && readMethod == null + && !isFieldExplicitlyVisible()); + } + + private boolean isFieldExplicitlyVisible() { + return field != null && (context.annotations().getAnnotation(field, JacksonConstants.JSON_VIEW) != null + || isUnhidden(field) + || context.annotations().getAnnotation(field, JacksonConstants.JSON_PROPERTY) != null); } public boolean isReadOnly() { @@ -692,8 +704,10 @@ private void processVisibility(AnnotationScannerContext context, AnnotationTarge if (target.kind() == Kind.METHOD) { if (isAccessor(context, target.asMethod())) { this.writeOnly = true; + this.ignoredReadMethod = target.asMethod(); } else { this.readOnly = true; + this.ignoredWriteMethod = target.asMethod(); } if (this.readOnly && this.writeOnly) { diff --git a/core/src/test/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolverTests.java b/core/src/test/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolverTests.java index 3e1a1c568..ca5538a28 100644 --- a/core/src/test/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolverTests.java +++ b/core/src/test/java/io/smallrye/openapi/runtime/scanner/dataobject/TypeResolverTests.java @@ -883,6 +883,46 @@ public void setField3(String field3) { Stream.of("field0", "field1", "field2", "field3").forEach(f -> assertFalse(p3.get(f).isIgnored())); } + @Test + /* + * Issue: https://github.com/smallrye/smallrye-open-api/issues/2412 + */ + void testJsonViewExcludesGetterOnlyProperty() { + class Views { + class Public { + } + + class Private { + } + } + + @SuppressWarnings("unused") + class Bean { + private String field0; + private String field1; + + public String getField0() { + return field0; + } + + public void setField0(String field0) { + this.field0 = field0; + } + + @JsonView(Views.Private.class) + public String getField1() { + return field1; + } + } + + AnnotationScannerContext context = buildContext(emptyConfig(), Bean.class, Views.Private.class, Views.Public.class); + context.getJsonViews().put(Type.create(DotName.createSimple(Views.Public.class), Type.Kind.CLASS), true); + + Map properties = getProperties(context, Bean.class); + assertFalse(properties.get("field0").isIgnored()); + assertTrue(properties.get("field1").isIgnored()); + } + /* * Issue: https://github.com/smallrye/smallrye-open-api/issues/1817 */