Support Spring MVC ResponseBodyAdvice,#34

This commit is contained in:
oppofind 2020-11-05 23:57:45 +08:00
parent f9c4a09394
commit 8e26a7217b
9 changed files with 377 additions and 235 deletions

View File

@ -7,6 +7,7 @@
2. 增加对抽象Controller方法的解析。
3. 修改阿里版本dubbo注解名称解析错误 。
4. 修改模拟值生成错误。
5. 支持ResponseBodyAdvice通用接口响应包装设置。
#### 版本号1.9.7
- 更新日期: 2020-10-24
- 更新内容:

View File

@ -148,9 +148,12 @@ When you need to use smart-doc to generate more API document information, you ca
"className": "org.springframework.data.domain.Pageable",
"replacementClassName": "com.power.doc.model.PageRequestDto" //Use custom PageRequestDto instead of JPA Pageable for document rendering.
}],
"apiConstants": [{////Configure your own constant class, smart-doc automatically replaces with a specific value when parsing to a constant
"apiConstants": [{//Configure your own constant class, smart-doc automatically replaces with a specific value when parsing to a constant
"constantsClassName": "com.power.doc.constants.RequestParamConstant"
}],
"responseBodyAdvice":{ //Support ResponseBodyAdvice
"className":"com.power.common.model.CommonResult" // Standard POJO for Response
},
  "requestHeaders": [// Set global request headers, no need to set
    {
      "name": "token",//header name

View File

@ -161,6 +161,9 @@ smart-doc官方目前已经开发完成[Maven插件](https://gitee.com/smart-doc
"apiConstants": [{//从1.8.9开始配置自己的常量类smart-doc在解析到常量时自动替换为具体的值
"constantsClassName": "com.power.doc.constants.RequestParamConstant"
}],
"responseBodyAdvice":{ //自smart-doc 1.9.8起ResponseBodyAdvice统一返回设置可用ignoreResponseBodyAdvice tag来忽略
"className":"com.power.common.model.CommonResult" //通用响应体
},
"sourceCodePaths": [ //设置代码路径, 插件已经能够自动下载发布的源码包,没必要配置
{
"path": "src/main/java",

View File

@ -1,191 +1,203 @@
/*
* smart-doc https://github.com/shalousun/smart-doc
*
* Copyright (C) 2018-2020 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.power.doc.builder;
import com.power.common.constants.Charset;
import com.power.common.util.CollectionUtil;
import com.power.common.util.StringUtil;
import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.model.*;
import com.power.doc.utils.JavaClassUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.power.doc.constants.DocGlobalConstants.DEFAULT_SERVER_URL;
/**
* @author yu 2019/12/21.
*/
public class ProjectDocConfigBuilder {
private JavaProjectBuilder javaProjectBuilder;
private Map<String, JavaClass> classFilesMap = new ConcurrentHashMap<>();
private Map<String, CustomRespField> customRespFieldMap = new ConcurrentHashMap<>();
private Map<String, String> replaceClassMap = new ConcurrentHashMap<>();
private Map<String, String> constantsMap = new ConcurrentHashMap<>();
private String serverUrl;
private ApiConfig apiConfig;
public ProjectDocConfigBuilder(ApiConfig apiConfig, JavaProjectBuilder javaProjectBuilder) {
if (null == apiConfig) {
throw new NullPointerException("ApiConfig can't be null.");
}
this.apiConfig = apiConfig;
if (Objects.isNull(javaProjectBuilder)) {
javaProjectBuilder = new JavaProjectBuilder();
}
if (StringUtil.isEmpty(apiConfig.getServerUrl())) {
this.serverUrl = DEFAULT_SERVER_URL;
} else {
this.serverUrl = apiConfig.getServerUrl();
}
javaProjectBuilder.setEncoding(Charset.DEFAULT_CHARSET);
this.javaProjectBuilder = javaProjectBuilder;
this.loadJavaSource(apiConfig.getSourceCodePaths(), this.javaProjectBuilder);
this.initClassFilesMap();
this.initCustomResponseFieldsMap(apiConfig);
this.initReplaceClassMap(apiConfig);
this.initConstants(apiConfig);
}
public JavaClass getClassByName(String simpleName) {
JavaClass cls = javaProjectBuilder.getClassByName(simpleName);
List<DocJavaField> fieldList = JavaClassUtil.getFields(cls, 0, new HashSet<>());
// handle inner class
if (Objects.isNull(cls.getFields()) || fieldList.isEmpty()) {
cls = classFilesMap.get(simpleName);
} else {
List<JavaClass> classList = cls.getNestedClasses();
for (JavaClass javaClass : classList) {
classFilesMap.put(javaClass.getFullyQualifiedName(), javaClass);
}
}
return cls;
}
private void loadJavaSource(List<SourceCodePath> paths, JavaProjectBuilder builder) {
if (CollectionUtil.isEmpty(paths)) {
builder.addSourceTree(new File(DocGlobalConstants.PROJECT_CODE_PATH));
} else {
for (SourceCodePath path : paths) {
if (null == path) {
continue;
}
String strPath = path.getPath();
if (StringUtil.isNotEmpty(strPath)) {
strPath = strPath.replace("\\", "/");
builder.addSourceTree(new File(strPath));
}
}
}
}
private void initClassFilesMap() {
Collection<JavaClass> javaClasses = javaProjectBuilder.getClasses();
for (JavaClass cls : javaClasses) {
classFilesMap.put(cls.getFullyQualifiedName(), cls);
}
}
private void initCustomResponseFieldsMap(ApiConfig config) {
if (CollectionUtil.isNotEmpty(config.getCustomResponseFields())) {
for (CustomRespField field : config.getCustomResponseFields()) {
customRespFieldMap.put(field.getName(), field);
}
}
}
private void initReplaceClassMap(ApiConfig config) {
if (CollectionUtil.isNotEmpty(config.getApiObjectReplacements())) {
for (ApiObjectReplacement replace : config.getApiObjectReplacements()) {
replaceClassMap.put(replace.getClassName(), replace.getReplacementClassName());
}
}
}
private void initConstants(ApiConfig config) {
List<ApiConstant> apiConstants;
if (CollectionUtil.isEmpty(config.getApiConstants())) {
apiConstants = new ArrayList<>();
} else {
apiConstants = config.getApiConstants();
}
try {
for (ApiConstant apiConstant : apiConstants) {
Class<?> clzz = apiConstant.getConstantsClass();
if (Objects.isNull(clzz)) {
if (StringUtil.isEmpty(apiConstant.getConstantsClassName())) {
throw new RuntimeException("Enum class name can't be null.");
}
clzz = Class.forName(apiConstant.getConstantsClassName());
}
constantsMap.putAll(JavaClassUtil.getFinalFieldValue(clzz));
}
} catch (ClassNotFoundException | IllegalAccessException e) {
e.printStackTrace();
}
}
public JavaProjectBuilder getJavaProjectBuilder() {
return javaProjectBuilder;
}
public Map<String, JavaClass> getClassFilesMap() {
return classFilesMap;
}
public Map<String, CustomRespField> getCustomRespFieldMap() {
return customRespFieldMap;
}
public String getServerUrl() {
return serverUrl;
}
public ApiConfig getApiConfig() {
return apiConfig;
}
public Map<String, String> getReplaceClassMap() {
return replaceClassMap;
}
public Map<String, String> getConstantsMap() {
return constantsMap;
}
}
/*
* smart-doc https://github.com/shalousun/smart-doc
*
* Copyright (C) 2018-2020 smart-doc
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package com.power.doc.builder;
import com.power.common.constants.Charset;
import com.power.common.util.CollectionUtil;
import com.power.common.util.StringUtil;
import com.power.doc.constants.DocGlobalConstants;
import com.power.doc.model.*;
import com.power.doc.utils.JavaClassUtil;
import com.thoughtworks.qdox.JavaProjectBuilder;
import com.thoughtworks.qdox.model.JavaClass;
import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import static com.power.doc.constants.DocGlobalConstants.DEFAULT_SERVER_URL;
/**
* @author yu 2019/12/21.
*/
public class ProjectDocConfigBuilder {
private JavaProjectBuilder javaProjectBuilder;
private Map<String, JavaClass> classFilesMap = new ConcurrentHashMap<>();
private Map<String, CustomRespField> customRespFieldMap = new ConcurrentHashMap<>();
private Map<String, String> replaceClassMap = new ConcurrentHashMap<>();
private Map<String, String> constantsMap = new ConcurrentHashMap<>();
private String serverUrl;
private ApiConfig apiConfig;
public ProjectDocConfigBuilder(ApiConfig apiConfig, JavaProjectBuilder javaProjectBuilder) {
if (null == apiConfig) {
throw new NullPointerException("ApiConfig can't be null.");
}
this.apiConfig = apiConfig;
if (Objects.isNull(javaProjectBuilder)) {
javaProjectBuilder = new JavaProjectBuilder();
}
if (StringUtil.isEmpty(apiConfig.getServerUrl())) {
this.serverUrl = DEFAULT_SERVER_URL;
} else {
this.serverUrl = apiConfig.getServerUrl();
}
javaProjectBuilder.setEncoding(Charset.DEFAULT_CHARSET);
this.javaProjectBuilder = javaProjectBuilder;
this.loadJavaSource(apiConfig.getSourceCodePaths(), this.javaProjectBuilder);
this.initClassFilesMap();
this.initCustomResponseFieldsMap(apiConfig);
this.initReplaceClassMap(apiConfig);
this.initConstants(apiConfig);
this.checkResponseBodyAdvice(apiConfig);
}
public JavaClass getClassByName(String simpleName) {
JavaClass cls = javaProjectBuilder.getClassByName(simpleName);
List<DocJavaField> fieldList = JavaClassUtil.getFields(cls, 0, new HashSet<>());
// handle inner class
if (Objects.isNull(cls.getFields()) || fieldList.isEmpty()) {
cls = classFilesMap.get(simpleName);
} else {
List<JavaClass> classList = cls.getNestedClasses();
for (JavaClass javaClass : classList) {
classFilesMap.put(javaClass.getFullyQualifiedName(), javaClass);
}
}
return cls;
}
private void loadJavaSource(List<SourceCodePath> paths, JavaProjectBuilder builder) {
if (CollectionUtil.isEmpty(paths)) {
builder.addSourceTree(new File(DocGlobalConstants.PROJECT_CODE_PATH));
} else {
for (SourceCodePath path : paths) {
if (null == path) {
continue;
}
String strPath = path.getPath();
if (StringUtil.isNotEmpty(strPath)) {
strPath = strPath.replace("\\", "/");
builder.addSourceTree(new File(strPath));
}
}
}
}
private void initClassFilesMap() {
Collection<JavaClass> javaClasses = javaProjectBuilder.getClasses();
for (JavaClass cls : javaClasses) {
classFilesMap.put(cls.getFullyQualifiedName(), cls);
}
}
private void initCustomResponseFieldsMap(ApiConfig config) {
if (CollectionUtil.isNotEmpty(config.getCustomResponseFields())) {
for (CustomRespField field : config.getCustomResponseFields()) {
customRespFieldMap.put(field.getName(), field);
}
}
}
private void initReplaceClassMap(ApiConfig config) {
if (CollectionUtil.isNotEmpty(config.getApiObjectReplacements())) {
for (ApiObjectReplacement replace : config.getApiObjectReplacements()) {
replaceClassMap.put(replace.getClassName(), replace.getReplacementClassName());
}
}
}
private void initConstants(ApiConfig config) {
List<ApiConstant> apiConstants;
if (CollectionUtil.isEmpty(config.getApiConstants())) {
apiConstants = new ArrayList<>();
} else {
apiConstants = config.getApiConstants();
}
try {
for (ApiConstant apiConstant : apiConstants) {
Class<?> clzz = apiConstant.getConstantsClass();
if (Objects.isNull(clzz)) {
if (StringUtil.isEmpty(apiConstant.getConstantsClassName())) {
throw new RuntimeException("Enum class name can't be null.");
}
clzz = Class.forName(apiConstant.getConstantsClassName());
}
constantsMap.putAll(JavaClassUtil.getFinalFieldValue(clzz));
}
} catch (ClassNotFoundException | IllegalAccessException e) {
e.printStackTrace();
}
}
private void checkResponseBodyAdvice(ApiConfig config) {
ResponseBodyAdvice responseBodyAdvice = config.getResponseBodyAdvice();
if (Objects.nonNull(responseBodyAdvice) && StringUtil.isNotEmpty(responseBodyAdvice.getClassName())) {
try {
Class.forName(responseBodyAdvice.getClassName());
}catch (ClassNotFoundException e){
throw new RuntimeException("Can't find class "+responseBodyAdvice.getClassName()+" for ResponseBodyAdvice.");
}
}
}
public JavaProjectBuilder getJavaProjectBuilder() {
return javaProjectBuilder;
}
public Map<String, JavaClass> getClassFilesMap() {
return classFilesMap;
}
public Map<String, CustomRespField> getCustomRespFieldMap() {
return customRespFieldMap;
}
public String getServerUrl() {
return serverUrl;
}
public ApiConfig getApiConfig() {
return apiConfig;
}
public Map<String, String> getReplaceClassMap() {
return replaceClassMap;
}
public Map<String, String> getConstantsMap() {
return constantsMap;
}
}

View File

@ -59,4 +59,9 @@ public interface DocTags {
* custom @order tag
*/
String ORDER = "order";
/**
* Ignore ResponseBodyAdvice
*/
String IGNORE_RESPONSE_BODY_ADVICE = "ignoreResponseBodyAdvice";
}

View File

@ -34,6 +34,8 @@ import com.thoughtworks.qdox.model.*;
import java.util.*;
import static com.power.doc.constants.DocTags.IGNORE_RESPONSE_BODY_ADVICE;
/**
* @author yu 2019/12/21.
@ -43,8 +45,8 @@ public class JsonBuildHelper {
/**
* build return json
*
* @param docJavaMethod The JavaMethod object
* @param builder ProjectDocConfigBuilder builder
* @param docJavaMethod The JavaMethod object
* @param builder ProjectDocConfigBuilder builder
* @return String
*/
public static String buildReturnJson(DocJavaMethod docJavaMethod, ProjectDocConfigBuilder builder) {
@ -52,7 +54,17 @@ public class JsonBuildHelper {
if (method.getReturns().isVoid()) {
return "This api return nothing.";
}
ApiReturn apiReturn = DocClassUtil.processReturnType(method.getReturnType().getGenericCanonicalName());
String returnTypeGenericCanonicalName = method.getReturnType().getGenericCanonicalName();
if (Objects.nonNull(builder.getApiConfig().getResponseBodyAdvice())
&& Objects.isNull(method.getTagByName(IGNORE_RESPONSE_BODY_ADVICE))) {
String responseBodyAdvice = builder.getApiConfig().getResponseBodyAdvice().getClassName();
StringBuilder sb = new StringBuilder();
sb.append(responseBodyAdvice)
.append("<")
.append(returnTypeGenericCanonicalName).append(">");
returnTypeGenericCanonicalName = sb.toString();
}
ApiReturn apiReturn = DocClassUtil.processReturnType(returnTypeGenericCanonicalName);
String typeName = apiReturn.getSimpleName();
Map<String, JavaType> actualTypesMap = docJavaMethod.getActualTypesMap();
String returnType = apiReturn.getGenericCanonicalName();
@ -89,7 +101,7 @@ public class JsonBuildHelper {
}
int nextLevel = counter + 1;
registryClasses.put(typeName, typeName);
if (JavaClassValidateUtil.isMvcIgnoreParams(typeName,builder.getApiConfig().getIgnoreRequestParams())) {
if (JavaClassValidateUtil.isMvcIgnoreParams(typeName, builder.getApiConfig().getIgnoreRequestParams())) {
if (DocGlobalConstants.MODE_AND_VIEW_FULLY.equals(typeName)) {
return "Forward or redirect to a page view.";
} else {

View File

@ -247,6 +247,12 @@ public class ApiConfig {
*/
private boolean displayActualType;
/**
* Support Spring MVC ResponseBodyAdvice
* @since 1.9.8
*/
private ResponseBodyAdvice responseBodyAdvice;
public String getServerUrl() {
return serverUrl;
}
@ -540,44 +546,90 @@ public class ApiConfig {
this.displayActualType = displayActualType;
}
public ResponseBodyAdvice getResponseBodyAdvice() {
return responseBodyAdvice;
}
public void setResponseBodyAdvice(ResponseBodyAdvice responseBodyAdvice) {
this.responseBodyAdvice = responseBodyAdvice;
}
@Override
public String toString() {
return "ApiConfig{" +
"serverUrl='" + serverUrl + '\'' +
", isStrict=" + isStrict +
", allInOne=" + allInOne +
", outPath='" + outPath + '\'' +
", sourceCodePaths=" + sourceCodePaths +
", requestHeaders=" + requestHeaders +
", coverOld=" + coverOld +
", customResponseFields=" + customResponseFields +
", errorCodes=" + errorCodes +
", packageFilters='" + packageFilters + '\'' +
", revisionLogs=" + revisionLogs +
", md5EncryptedHtmlName=" + md5EncryptedHtmlName +
", language=" + language +
", adoc=" + adoc +
", dataDictionaries=" + dataDictionaries +
", errorCodeDictionaries=" + errorCodeDictionaries +
", apiObjectReplacements=" + apiObjectReplacements +
", rpcApiDependencies=" + rpcApiDependencies +
", apiConstants=" + apiConstants +
", projectName='" + projectName + '\'' +
", skipTransientField=" + skipTransientField +
", showAuthor=" + showAuthor +
", requestFieldToUnderline=" + requestFieldToUnderline +
", responseFieldToUnderline=" + responseFieldToUnderline +
", sortByTitle=" + sortByTitle +
", showJavaType=" + showJavaType +
", inlineEnum=" + inlineEnum +
", rpcConsumerConfig='" + rpcConsumerConfig + '\'' +
", recursionLimit=" + recursionLimit +
", requestExample=" + requestExample +
", responseExample=" + responseExample +
", allInOneDocFileName='" + allInOneDocFileName + '\'' +
", paramsDataToTree=" + paramsDataToTree +
", ignoreRequestParams=" + ignoreRequestParams +
", displayActualType=" + displayActualType +
'}';
final StringBuilder sb = new StringBuilder("{");
sb.append("\"serverUrl\":\"")
.append(serverUrl).append('\"');
sb.append(",\"isStrict\":")
.append(isStrict);
sb.append(",\"allInOne\":")
.append(allInOne);
sb.append(",\"outPath\":\"")
.append(outPath).append('\"');
sb.append(",\"sourceCodePaths\":")
.append(sourceCodePaths);
sb.append(",\"requestHeaders\":")
.append(requestHeaders);
sb.append(",\"coverOld\":")
.append(coverOld);
sb.append(",\"customResponseFields\":")
.append(customResponseFields);
sb.append(",\"errorCodes\":")
.append(errorCodes);
sb.append(",\"packageFilters\":\"")
.append(packageFilters).append('\"');
sb.append(",\"revisionLogs\":")
.append(revisionLogs);
sb.append(",\"md5EncryptedHtmlName\":")
.append(md5EncryptedHtmlName);
sb.append(",\"language\":")
.append(language);
sb.append(",\"adoc\":")
.append(adoc);
sb.append(",\"dataDictionaries\":")
.append(dataDictionaries);
sb.append(",\"errorCodeDictionaries\":")
.append(errorCodeDictionaries);
sb.append(",\"apiObjectReplacements\":")
.append(apiObjectReplacements);
sb.append(",\"rpcApiDependencies\":")
.append(rpcApiDependencies);
sb.append(",\"apiConstants\":")
.append(apiConstants);
sb.append(",\"projectName\":\"")
.append(projectName).append('\"');
sb.append(",\"skipTransientField\":")
.append(skipTransientField);
sb.append(",\"showAuthor\":")
.append(showAuthor);
sb.append(",\"requestFieldToUnderline\":")
.append(requestFieldToUnderline);
sb.append(",\"responseFieldToUnderline\":")
.append(responseFieldToUnderline);
sb.append(",\"sortByTitle\":")
.append(sortByTitle);
sb.append(",\"showJavaType\":")
.append(showJavaType);
sb.append(",\"inlineEnum\":")
.append(inlineEnum);
sb.append(",\"rpcConsumerConfig\":\"")
.append(rpcConsumerConfig).append('\"');
sb.append(",\"recursionLimit\":")
.append(recursionLimit);
sb.append(",\"requestExample\":")
.append(requestExample);
sb.append(",\"responseExample\":")
.append(responseExample);
sb.append(",\"allInOneDocFileName\":\"")
.append(allInOneDocFileName).append('\"');
sb.append(",\"paramsDataToTree\":")
.append(paramsDataToTree);
sb.append(",\"ignoreRequestParams\":")
.append(ignoreRequestParams);
sb.append(",\"displayActualType\":")
.append(displayActualType);
sb.append(",\"responseBodyAdvice\":")
.append(responseBodyAdvice);
sb.append('}');
return sb.toString();
}
}

View File

@ -0,0 +1,45 @@
package com.power.doc.model;
/**
* @since 1.9.8
* @author yu 2020/11/5.
*/
public class ResponseBodyAdvice {
private String className;
private String dataField;
public static ResponseBodyAdvice builder(){
return new ResponseBodyAdvice();
}
public String getClassName() {
return className;
}
public ResponseBodyAdvice setClassName(String className) {
this.className = className;
return this;
}
public String getDataField() {
return dataField;
}
public ResponseBodyAdvice setDataField(String dataField) {
this.dataField = dataField;
return this;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"className\":\"")
.append(className).append('\"');
sb.append(",\"dataField\":\"")
.append(dataField).append('\"');
sb.append('}');
return sb.toString();
}
}

View File

@ -38,6 +38,7 @@ import com.thoughtworks.qdox.model.JavaType;
import java.util.*;
import static com.power.doc.constants.DocGlobalConstants.NO_COMMENTS_FOUND;
import static com.power.doc.constants.DocTags.IGNORE_RESPONSE_BODY_ADVICE;
/**
* @author yu 2019/12/21.
@ -96,9 +97,17 @@ public interface IDocBuildTemplate<T> {
if (method.getReturns().isVoid()) {
return null;
}
String returnTypeGenericCanonicalName = method.getReturnType().getGenericCanonicalName();
if (Objects.nonNull(projectBuilder.getApiConfig().getResponseBodyAdvice())
&& Objects.isNull(method.getTagByName(IGNORE_RESPONSE_BODY_ADVICE))) {
String responseBodyAdvice = projectBuilder.getApiConfig().getResponseBodyAdvice().getClassName();
returnTypeGenericCanonicalName = new StringBuffer()
.append(responseBodyAdvice)
.append("<")
.append(returnTypeGenericCanonicalName).append(">").toString();
}
Map<String, JavaType> actualTypesMap = docJavaMethod.getActualTypesMap();
ApiReturn apiReturn = DocClassUtil.processReturnType(method.getReturnType().getGenericCanonicalName());
ApiReturn apiReturn = DocClassUtil.processReturnType(returnTypeGenericCanonicalName);
String returnType = apiReturn.getGenericCanonicalName();
if (Objects.nonNull(actualTypesMap)) {
for (Map.Entry<String, JavaType> entry : actualTypesMap.entrySet()) {