Skip to content
This repository was archived by the owner on Nov 24, 2022. It is now read-only.

Commit daba48f

Browse files
committed
Merge remote-tracking branch 'origin/master' into 2.0-OpenAPITools
2 parents 339d24d + ada75b6 commit daba48f

6 files changed

Lines changed: 724 additions & 39 deletions

File tree

modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/OpenAPIV3Parser.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -197,19 +197,36 @@ public SwaggerParseResult readContents(String swaggerAsString, List<Authorizatio
197197
return result;
198198
}
199199

200+
/**
201+
* Locates extensions on the current thread class loader and then, if it differs
202+
* from this class classloader (as in OSGi), locates extensions from this
203+
* class classloader as well.
204+
*
205+
* @return a list of extensions
206+
*/
200207
protected List<SwaggerParserExtension> getExtensions() {
208+
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
209+
List<SwaggerParserExtension> extensions = getExtensions(tccl);
210+
ClassLoader cl = SwaggerParserExtension.class.getClassLoader();
211+
if (cl != tccl) {
212+
extensions.addAll(getExtensions(cl));
213+
}
214+
extensions.add(0, new OpenAPIV3Parser());
215+
return extensions;
216+
}
217+
218+
protected List<SwaggerParserExtension> getExtensions(ClassLoader cl) {
201219
List<SwaggerParserExtension> extensions = new ArrayList<>();
202220

203-
ServiceLoader<SwaggerParserExtension> loader = ServiceLoader.load(SwaggerParserExtension.class);
221+
ServiceLoader<SwaggerParserExtension> loader = ServiceLoader.load(SwaggerParserExtension.class, cl);
204222
Iterator<SwaggerParserExtension> itr = loader.iterator();
205223
while (itr.hasNext()) {
206224
extensions.add(itr.next());
207225
}
208-
extensions.add(0, new OpenAPIV3Parser());
209226
return extensions;
210227
}
211228

212-
/**
229+
/**
213230
* Transform the swagger-model version of AuthorizationValue into a parser-specific one, to avoid
214231
* dependencies across extensions
215232
*

modules/swagger-parser-v3/src/main/java/io/swagger/v3/parser/util/OpenAPIDeserializer.java

Lines changed: 185 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,11 @@
1717
import io.swagger.v3.oas.models.info.Contact;
1818
import io.swagger.v3.oas.models.info.Info;
1919
import io.swagger.v3.oas.models.media.ArraySchema;
20+
import io.swagger.v3.oas.models.media.ByteArraySchema;
2021
import io.swagger.v3.oas.models.media.ComposedSchema;
2122
import io.swagger.v3.oas.models.media.Content;
23+
import io.swagger.v3.oas.models.media.DateSchema;
24+
import io.swagger.v3.oas.models.media.DateTimeSchema;
2225
import io.swagger.v3.oas.models.media.Discriminator;
2326
import io.swagger.v3.oas.models.media.Encoding;
2427
import io.swagger.v3.oas.models.media.MediaType;
@@ -46,16 +49,23 @@
4649
import io.swagger.v3.oas.models.servers.ServerVariables;
4750
import io.swagger.v3.parser.core.models.SwaggerParseResult;
4851
import io.swagger.v3.core.util.Json;
52+
import io.swagger.v3.core.util.RefUtils;
53+
4954
import org.apache.commons.lang3.StringUtils;
5055

56+
import static io.swagger.v3.core.util.RefUtils.extractSimpleName;
57+
5158
import java.math.BigDecimal;
5259
import java.net.URI;
5360
import java.net.URISyntaxException;
5461
import java.net.URL;
62+
import java.text.ParseException;
5563
import java.util.*;
64+
import java.util.regex.Matcher;
5665
import java.util.regex.Pattern;
5766
import java.util.stream.Collectors;
5867
import java.util.stream.Stream;
68+
import static java.util.Calendar.*;
5969

6070

6171
public class OpenAPIDeserializer {
@@ -90,6 +100,9 @@ public class OpenAPIDeserializer {
90100
private static final String COOKIE_PARAMETER = "cookie";
91101
private static final String PATH_PARAMETER = "path";
92102
private static final String HEADER_PARAMETER = "header";
103+
private static final Pattern RFC3339_DATE_TIME_PATTERN = Pattern.compile( "^(\\d{4})-(\\d{2})-(\\d{2})T(\\d{2}):(\\d{2}):(\\d{2})(\\.\\d+)?((Z)|([+-]\\d{2}:\\d{2}))$");
104+
private static final Pattern RFC3339_DATE_PATTERN = Pattern.compile( "^(\\d{4})-(\\d{2})-(\\d{2})$");
105+
93106
private Components components;
94107
private final Set<String> operationIDs = new HashSet<>();
95108

@@ -1408,13 +1421,25 @@ public List<Parameter> getParameterList(ArrayNode obj, String location, ParseRes
14081421
}
14091422
Set<String> filter = new HashSet<>();
14101423

1411-
for(Parameter param:parameters) {
1424+
parameters.stream().map(this::getParameterDefinition).forEach(param -> {
14121425
if(!filter.add(param.getName()+"#"+param.getIn())) {
14131426
result.warning(location,"There are duplicate parameter values");
14141427
}
1415-
}
1428+
});
14161429
return parameters;
14171430
}
1431+
1432+
private Parameter getParameterDefinition(Parameter parameter) {
1433+
if (parameter.get$ref() == null) {
1434+
return parameter;
1435+
}
1436+
Object parameterSchemaName = extractSimpleName(parameter.get$ref()).getLeft();
1437+
return Optional.ofNullable(components)
1438+
.map(Components::getParameters)
1439+
.map(parameters -> parameters.get(parameterSchemaName))
1440+
.orElse(parameter);
1441+
1442+
}
14181443

14191444
public Parameter getParameter(ObjectNode obj, String location, ParseResult result) {
14201445
if (obj == null) {
@@ -2185,16 +2210,21 @@ public Schema getSchema(ObjectNode node, String location, ParseResult result){
21852210
for (JsonNode n : enumArray) {
21862211
if (n.isNumber()) {
21872212
schema.addEnumItemObject(n.numberValue());
2188-
}else if (n.isValueNode()) {
2189-
schema.addEnumItemObject(n.asText());
2213+
} else if (n.isValueNode()) {
2214+
try {
2215+
schema.addEnumItemObject( getDecodedObject( schema, n.asText(null)));
2216+
}
2217+
catch( ParseException e) {
2218+
result.invalidType( location, String.format( "enum=`%s`", e.getMessage()), schema.getFormat(), n);
2219+
}
21902220
} else {
21912221
result.invalidType(location, "enum", "value", n);
21922222
}
21932223
}
21942224
}
21952225

21962226
value = getString("type",node,false,location,result);
2197-
if (StringUtils.isNotBlank(value)) {
2227+
if (StringUtils.isNotBlank(value) && StringUtils.isBlank(schema.getType())) {
21982228
schema.setType(value);
21992229
}else{
22002230
// may have an enum where type can be inferred
@@ -2267,35 +2297,41 @@ public Schema getSchema(ObjectNode node, String location, ParseResult result){
22672297

22682298
//sets default value according to the schema type
22692299
if(node.get("default")!= null) {
2270-
if(schema.getType().equals("array")) {
2271-
ArrayNode array = getArray("default", node, false, location, result);
2272-
if (array != null) {
2273-
schema.setDefault(array);
2274-
}
2275-
}else if(schema.getType().equals("string")) {
2276-
value = getString("default", node, false, location, result);
2277-
if (value != null) {
2278-
schema.setDefault(value);
2279-
}
2280-
}else if(schema.getType().equals("boolean")) {
2281-
bool = getBoolean("default", node, false, location, result);
2282-
if (bool != null) {
2283-
schema.setDefault(bool);
2284-
}
2285-
}else if(schema.getType().equals("object")) {
2286-
Object object = getObject("default", node, false, location, result);
2287-
if (object != null) {
2288-
schema.setDefault(object);
2289-
}
2290-
} else if(schema.getType().equals("integer")) {
2291-
Integer number = getInteger("default", node, false, location, result);
2292-
if (number != null) {
2293-
schema.setDefault(number);
2294-
}
2295-
} else if(schema.getType().equals("number")) {
2296-
BigDecimal number = getBigDecimal("default", node, false, location, result);
2297-
if (number != null) {
2298-
schema.setDefault(number);
2300+
if(!StringUtils.isBlank(schema.getType())) {
2301+
if (schema.getType().equals("array")) {
2302+
ArrayNode array = getArray("default", node, false, location, result);
2303+
if (array != null) {
2304+
schema.setDefault(array);
2305+
}
2306+
} else if (schema.getType().equals("string")) {
2307+
value = getString("default", node, false, location, result);
2308+
if (value != null) {
2309+
try {
2310+
schema.setDefault(getDecodedObject(schema, value));
2311+
} catch (ParseException e) {
2312+
result.invalidType(location, String.format("default=`%s`", e.getMessage()), schema.getFormat(), node);
2313+
}
2314+
}
2315+
} else if (schema.getType().equals("boolean")) {
2316+
bool = getBoolean("default", node, false, location, result);
2317+
if (bool != null) {
2318+
schema.setDefault(bool);
2319+
}
2320+
} else if (schema.getType().equals("object")) {
2321+
Object object = getObject("default", node, false, location, result);
2322+
if (object != null) {
2323+
schema.setDefault(object);
2324+
}
2325+
} else if (schema.getType().equals("integer")) {
2326+
Integer number = getInteger("default", node, false, location, result);
2327+
if (number != null) {
2328+
schema.setDefault(number);
2329+
}
2330+
} else if (schema.getType().equals("number")) {
2331+
BigDecimal number = getBigDecimal("default", node, false, location, result);
2332+
if (number != null) {
2333+
schema.setDefault(number);
2334+
}
22992335
}
23002336
}
23012337
}
@@ -2359,6 +2395,121 @@ public Schema getSchema(ObjectNode node, String location, ParseResult result){
23592395
}
23602396

23612397

2398+
/**
2399+
* Decodes the given string and returns an object applicable to the given schema.
2400+
* Throws a ParseException if no applicable object can be recognized.
2401+
*/
2402+
private Object getDecodedObject( Schema schema, String objectString) throws ParseException {
2403+
Object object =
2404+
objectString == null?
2405+
null :
2406+
2407+
schema.getClass().equals( DateSchema.class)?
2408+
toDate( objectString) :
2409+
2410+
schema.getClass().equals( DateTimeSchema.class)?
2411+
toDateTime( objectString) :
2412+
2413+
schema.getClass().equals( ByteArraySchema.class)?
2414+
toBytes( objectString) :
2415+
2416+
objectString;
2417+
2418+
if( object == null && objectString != null) {
2419+
throw new ParseException( objectString, 0);
2420+
}
2421+
2422+
return object;
2423+
}
2424+
2425+
2426+
/**
2427+
* Returns the Date represented by the given RFC3339 date-time string.
2428+
* Returns null if this string can't be parsed as Date.
2429+
*/
2430+
private Date toDateTime( String dateString) {
2431+
// Note: For this conversion, regex matching is better than SimpleDateFormat, etc.
2432+
// Optional elements (e.g. milliseconds) are not directly handled by SimpleDateFormat.
2433+
// Also, SimpleDateFormat is not thread-safe.
2434+
Matcher matcher = RFC3339_DATE_TIME_PATTERN.matcher( dateString);
2435+
2436+
Date dateTime = null;
2437+
if( matcher.matches()) {
2438+
try {
2439+
String year = matcher.group(1);
2440+
String month = matcher.group(2);
2441+
String day = matcher.group(3);
2442+
String hour = matcher.group(4);
2443+
String min = matcher.group(5);
2444+
String sec = matcher.group(6);
2445+
String ms = matcher.group(7);
2446+
String zone = matcher.group(10);
2447+
2448+
Calendar calendar = Calendar.getInstance( TimeZone.getTimeZone( zone == null? "GMT" : "GMT" + zone));
2449+
calendar.set( YEAR, Integer.parseInt( year));
2450+
calendar.set( MONTH, Integer.parseInt( month) - 1);
2451+
calendar.set( DAY_OF_MONTH, Integer.parseInt( day));
2452+
calendar.set( HOUR_OF_DAY, Integer.parseInt( hour));
2453+
calendar.set( MINUTE, Integer.parseInt( min));
2454+
calendar.set( SECOND, Integer.parseInt( sec));
2455+
calendar.set( MILLISECOND, ms == null? 0 : (int) (Double.parseDouble( ms) * 1000));
2456+
2457+
dateTime = calendar.getTime();
2458+
}
2459+
catch( Exception ignore) {
2460+
}
2461+
}
2462+
2463+
return dateTime;
2464+
}
2465+
2466+
2467+
/**
2468+
* Returns the Date represented by the given RFC3339 full-date string.
2469+
* Returns null if this string can't be parsed as Date.
2470+
*/
2471+
private Date toDate( String dateString) {
2472+
Matcher matcher = RFC3339_DATE_PATTERN.matcher( dateString);
2473+
2474+
Date date = null;
2475+
if( matcher.matches()) {
2476+
String year = matcher.group(1);
2477+
String month = matcher.group(2);
2478+
String day = matcher.group(3);
2479+
2480+
try {
2481+
date=
2482+
new Calendar.Builder()
2483+
.setDate( Integer.parseInt( year), Integer.parseInt( month) - 1, Integer.parseInt( day))
2484+
.build()
2485+
.getTime();
2486+
}
2487+
catch( Exception ignore) {
2488+
}
2489+
}
2490+
2491+
return date;
2492+
}
2493+
2494+
2495+
/**
2496+
* Returns the byte array represented by the given base64-encoded string.
2497+
* Returns null if this string is not a valid base64 encoding.
2498+
*/
2499+
private byte[] toBytes( String byteString) {
2500+
byte[] bytes;
2501+
2502+
try {
2503+
bytes = Base64.getDecoder().decode( byteString);
2504+
}
2505+
catch( Exception e) {
2506+
bytes = null;
2507+
}
2508+
2509+
return bytes;
2510+
}
2511+
2512+
23622513

23632514

23642515
public Map<String, Example> getExamples(ObjectNode obj, String location, ParseResult result) {

0 commit comments

Comments
 (0)