Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'required' attribute does not work in @Schema #1468

Closed
hokjoung opened this issue Jan 26, 2022 · 4 comments
Closed

'required' attribute does not work in @Schema #1468

hokjoung opened this issue Jan 26, 2022 · 4 comments
Labels
duplicate This issue or pull request already exists

Comments

@hokjoung
Copy link

hokjoung commented Jan 26, 2022

Describe the bug
the required attribute for the @Schema is not reflected on the openapi response.
any help is appreciated

untitled_and_untitled_and_payments-api_–_PaymentController_kt__payments-api_api_main__and_Swagger_UI

To Reproduce
Steps to reproduce the behavior:

  • What version of spring-boot you are using?
    2.3.7.RELEASE

  • What modules and versions of springdoc-openapi are you using?
    dependency("org.springdoc:springdoc-openapi-ui:1.5.13")
    dependency("org.springdoc:springdoc-openapi-kotlin:1.5.13")

  • What is the actual and the expected result using OpenAPI Description (yml or json)?
    actual:

{
   ...
   "PaymentKeyInRequest":{
      "required":[
         "amount",
         "customerEmail",
         "extraInfo",
         "orderId",
         "orderName",
         "productCode",
         "productDiscountCode",
         "productExpirationMonth",
         "productExpirationYear",
         "productNumber",
         "taxFreeAmount"
      ],
      "type":"object",
      "properties":{
         "amount":{
   ...
}

expected:

{
   ...
   "PaymentKeyInRequest":{
      "required":[
         "amount",
         "productCode",
         "customerName",
         "customerIdentityNumber"
      ],
      "type":"object",
      "properties":{
         "amount":{
   ...
}

Expected behavior

  • the value specifically given for the required attribute should be the final value for the field
@bnasslahsen bnasslahsen added the duplicate This issue or pull request already exists label Jan 26, 2022
@bnasslahsen
Copy link
Contributor

it's useless to create duplicates #1285
Read the contributing guidelines before opening tickets.

@hokjoung
Copy link
Author

#1285 (comment)
@bnasslahsen I'm not sure why this issue was marked wontfix and locked before the above comment was addressed properly.
It is a valid use case that I have raised above as well, whereby fields of public apis can be optional to the public but nonetheless be non-null with default values.
Regardless of scenarios, what could be the reasoning behind deciding to not use the required attribute, which has the sole purpose of specifically annotating whether a field is required or not, but rather opting to follow a narrowly scoped logic of nullability which is dependent on implementations.

*Also, my other issue was deleted. Issues are meant to be deleted when the posts are clearly vandalizing the space. Please be respectful of the community as a moderator.

@bnasslahsen
Copy link
Contributor

@hokjoung,

You are creating too many duplicates and it's just not productive. That's why your other duplicate issue were deleted.
As explained #1285: All val variable are from kotlin perspective is non-nullable. Consequently: com.fasterxml.jackson.module.kotlin.KotlinModule which is loaded by springdoc-openapi-kotlin will mark them as required. (This is not handled directly in the springdoc-openapi code)

Let me know if the workaround helps you:

  1. Remove the dependency springdoc-openapi-kotlin
  2. Add the two following classes to your project:
    SpringDocKotlinConfiguration.java
import kotlin.Deprecated;
import kotlin.coroutines.Continuation;
import org.springdoc.core.SpringDocUtils;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

/**
 * The type Spring doc kotlin configuration.
 * @author bnasslahsen
 */
@Lazy(false)
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Continuation.class)
@ConditionalOnWebApplication
public class SpringDocKotlinConfiguration {

	static {
		SpringDocUtils.getConfig().addRequestWrapperToIgnore(Continuation.class)
				.addDeprecatedType(Deprecated.class);
	}

	/**
	 * Kotlin coroutines return type parser kotlin coroutines return type parser.
	 *
	 * @return the kotlin coroutines return type parser
	 */
	@Bean
	@Lazy(false)
	@ConditionalOnMissingBean
	KotlinCoroutinesReturnTypeParser kotlinCoroutinesReturnTypeParser() {
		return new KotlinCoroutinesReturnTypeParser();
	}

}

And KotlinCoroutinesReturnTypeParser.java:

import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.Optional;

import kotlin.coroutines.Continuation;
import org.springdoc.core.ReturnTypeParser;

import org.springframework.core.MethodParameter;

/**
 * The type Kotlin coroutines return type parser.
 * @author bnasslahsen
 */
public class KotlinCoroutinesReturnTypeParser implements ReturnTypeParser {

	@Override
	public Type getReturnType(MethodParameter methodParameter) {
		Method method = methodParameter.getMethod();
		Type returnType = Object.class;
		assert method != null;
		Optional<Parameter> continuationParameter = Arrays.stream(method.getParameters())
				.filter(parameter -> parameter.getType().getCanonicalName().equals(Continuation.class.getCanonicalName()))
				.findFirst();
		if (continuationParameter.isPresent()) {
			Type continuationType = continuationParameter.get().getParameterizedType();
			if (continuationType instanceof ParameterizedType) {
				Type actualTypeArguments = ((ParameterizedType) continuationType).getActualTypeArguments()[0];
				if (actualTypeArguments instanceof WildcardType)
					returnType = ((WildcardType) actualTypeArguments).getLowerBounds()[0];
			}
		}
		return returnType;
	}
}
  1. Restart your application and test the result.

@JanCizmar
Copy link

Hi there. I really don't know why have you closed this issue and why you locked conversation in #1285. There is a difference between nullability and required in the schema. When I set @Schema annotation to this:

  @Schema(required = false, description = "Ho ho ho ", nullable = true)
  var format: ExportFormat = ExportFormat.JSON,

The format property is still required, even when it has a default value and the required is set to false. Why for the god's sake it ignores the @Schema annotation when it doesn't extract the required param correctly? This is a bug. This issue and the #1285 shouldn't be closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests

3 participants