Skip to content

Commit

Permalink
springdoc-openapi-webflux-ui 2.0.0-M7 + spring actuator + spring clou…
Browse files Browse the repository at this point in the history
…d crashes at startup. Fixes #1904
  • Loading branch information
bnasslahsen committed Nov 14, 2022
1 parent 2b44526 commit cb7b0a3
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -497,13 +497,12 @@ static class WebConversionServiceConfiguration {
/**
* Web conversion service provider web conversion service provider.
*
* @param genericConversionServiceList the web conversion service optional
* @return the web conversion service provider
*/
@Bean
@Lazy(false)
WebConversionServiceProvider webConversionServiceProvider(Optional<List<GenericConversionService>> genericConversionServiceList) {
return new WebConversionServiceProvider(genericConversionServiceList);
WebConversionServiceProvider webConversionServiceProvider() {
return new WebConversionServiceProvider();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,98 +23,133 @@
package org.springdoc.core.providers;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.lang3.reflect.FieldUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.GenericConverter.ConvertiblePair;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;

/**
* The type Web conversion service provider.
* @author bnasslashen
*/
public class WebConversionServiceProvider {

/**
* The constant CONVERTERS.
*/
private static final String CONVERTERS = "converters";

/**
* The constant LOGGER.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(WebConversionServiceProvider.class);

/**
* The Formatting conversion service.
*/
private GenericConversionService formattingConversionService;

/**
* Instantiates a new Web conversion service provider.
*
* @param webConversionServiceOptional the web conversion service optional
*/
public WebConversionServiceProvider(Optional<List<GenericConversionService>> webConversionServiceOptional) {
if (webConversionServiceOptional.isPresent()) {
List<GenericConversionService> conversionServiceList = webConversionServiceOptional.get();
for (GenericConversionService genericConversionService : conversionServiceList) {
if (genericConversionService instanceof FormattingConversionService) {
this.formattingConversionService = genericConversionService;
break;
public class WebConversionServiceProvider implements InitializingBean, ApplicationContextAware {

/**
* The constant CONVERTERS.
*/
private static final String CONVERTERS = "converters";

/**
* The constant LOGGER.
*/
private static final Logger LOGGER = LoggerFactory.getLogger(WebConversionServiceProvider.class);

/**
* The Formatting conversion service.
*/
private GenericConversionService formattingConversionService;


/**
* The Application context.
*/
private ApplicationContext applicationContext;

/**
* The constant SERVLET_APPLICATION_CONTEXT_CLASS.
*/
private static final String SERVLET_APPLICATION_CONTEXT_CLASS = "org.springframework.web.context.WebApplicationContext";

/**
* The constant REACTIVE_APPLICATION_CONTEXT_CLASS.
*/
private static final String REACTIVE_APPLICATION_CONTEXT_CLASS = "org.springframework.boot.web.reactive.context.ReactiveWebApplicationContext";

@Override
public void afterPropertiesSet() {
if (isAssignable(SERVLET_APPLICATION_CONTEXT_CLASS, this.applicationContext.getClass())) {
this.formattingConversionService = applicationContext.getBean("mvcConversionService", FormattingConversionService.class);
}
else if (isAssignable(REACTIVE_APPLICATION_CONTEXT_CLASS, this.applicationContext.getClass())) {
this.formattingConversionService = applicationContext.getBean("webFluxConversionService", FormattingConversionService.class);
}
else
formattingConversionService = new DefaultFormattingConversionService();
}

/**
* Attempts to convert {@code source} into the target type as described by {@code targetTypeDescriptor}.
*
* @param source the source
* @param targetTypeDescriptor the target type descriptor
* @return the converted source
*/
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor targetTypeDescriptor) {
return formattingConversionService.convert(source, targetTypeDescriptor);
}

/**
* Gets spring converted type.
*
* @param clazz the clazz
* @return the spring converted type
*/
public Class<?> getSpringConvertedType(Class<?> clazz) {
Class<?> result = clazz;
Field convertersField = FieldUtils.getDeclaredField(GenericConversionService.class, CONVERTERS, true);
if (convertersField != null) {
Object converters;
try {
converters = convertersField.get(formattingConversionService);
convertersField = FieldUtils.getDeclaredField(converters.getClass(), CONVERTERS, true);
Map<ConvertiblePair, Object> springConverters = (Map) convertersField.get(converters);
Optional<ConvertiblePair> convertiblePairOptional = springConverters.keySet().stream().filter(convertiblePair -> convertiblePair.getTargetType().equals(clazz)).findAny();
if (convertiblePairOptional.isPresent()) {
ConvertiblePair convertiblePair = convertiblePairOptional.get();
result = convertiblePair.getSourceType();
}
}
catch (IllegalAccessException e) {
LOGGER.warn(e.getMessage());
}
}
return result;
}
if (formattingConversionService == null)
formattingConversionService = new DefaultFormattingConversionService();
}

/**
* Attempts to convert {@code source} into the target type as described by {@code targetTypeDescriptor}.
*
* @param source the source
* @param targetTypeDescriptor the target type descriptor
* @return the converted source
*/
@Nullable
public Object convert(@Nullable Object source, TypeDescriptor targetTypeDescriptor) {
return formattingConversionService.convert(source, targetTypeDescriptor);
}

/**
* Gets spring converted type.
*
* @param clazz the clazz
* @return the spring converted type
*/
public Class<?> getSpringConvertedType(Class<?> clazz) {
Class<?> result = clazz;
Field convertersField = FieldUtils.getDeclaredField(GenericConversionService.class, CONVERTERS, true);
if(convertersField!=null) {
Object converters;

/**
* Is assignable boolean.
*
* @param target the target
* @param type the type
* @return the boolean
*/
private boolean isAssignable(String target, Class<?> type) {
try {
converters = convertersField.get(formattingConversionService);
convertersField = FieldUtils.getDeclaredField(converters.getClass(), CONVERTERS, true);
Map<ConvertiblePair, Object> springConverters = (Map) convertersField.get(converters);
Optional<ConvertiblePair> convertiblePairOptional = springConverters.keySet().stream().filter(convertiblePair -> convertiblePair.getTargetType().equals(clazz)).findAny();
if (convertiblePairOptional.isPresent()) {
ConvertiblePair convertiblePair = convertiblePairOptional.get();
result = convertiblePair.getSourceType();
}
return ClassUtils.resolveClassName(target, null).isAssignableFrom(type);
}
catch (IllegalAccessException e) {
LOGGER.warn(e.getMessage());
catch (Throwable ex) {
return false;
}
}
return result;
}

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

}

0 comments on commit cb7b0a3

Please sign in to comment.