Skip to content

Commit

Permalink
(issue swagger-api#1049) OpenAPIDeserializer: Rework handling of form…
Browse files Browse the repository at this point in the history
…atted string values using getDecodedObject()
  • Loading branch information
kerrykimbrough committed Mar 26, 2019
1 parent aeb9def commit fdad4e4
Show file tree
Hide file tree
Showing 2 changed files with 360 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,11 @@
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.ByteArraySchema;
import io.swagger.v3.oas.models.media.ComposedSchema;
import io.swagger.v3.oas.models.media.Content;
import io.swagger.v3.oas.models.media.DateSchema;
import io.swagger.v3.oas.models.media.DateTimeSchema;
import io.swagger.v3.oas.models.media.Discriminator;
import io.swagger.v3.oas.models.media.Encoding;
import io.swagger.v3.oas.models.media.MediaType;
Expand Down Expand Up @@ -52,10 +55,13 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.ParseException;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.util.Calendar.*;


public class OpenAPIDeserializer {
Expand Down Expand Up @@ -90,6 +96,9 @@ public class OpenAPIDeserializer {
private static final String COOKIE_PARAMETER = "cookie";
private static final String PATH_PARAMETER = "path";
private static final String HEADER_PARAMETER = "header";
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}))$");
private static final Pattern RFC3339_DATE_PATTERN = Pattern.compile( "^(\\d{4})-(\\d{2})-(\\d{2})$");

private Components components;
private final Set<String> operationIDs = new HashSet<>();

Expand Down Expand Up @@ -2185,8 +2194,13 @@ public Schema getSchema(ObjectNode node, String location, ParseResult result){
for (JsonNode n : enumArray) {
if (n.isNumber()) {
schema.addEnumItemObject(n.numberValue());
}else if (n.isValueNode()) {
schema.addEnumItemObject(n.asText());
} else if (n.isValueNode()) {
try {
schema.addEnumItemObject( getDecodedObject( schema, n.asText(null)));
}
catch( ParseException e) {
result.invalidType( location, String.format( "enum=`%s`", e.getMessage()), schema.getFormat(), n);
}
} else {
result.invalidType(location, "enum", "value", n);
}
Expand Down Expand Up @@ -2275,7 +2289,12 @@ public Schema getSchema(ObjectNode node, String location, ParseResult result){
}else if(schema.getType().equals("string")) {
value = getString("default", node, false, location, result);
if (value != null) {
schema.setDefault(value);
try {
schema.setDefault( getDecodedObject( schema, value));
}
catch( ParseException e) {
result.invalidType( location, String.format( "default=`%s`", e.getMessage()), schema.getFormat(), node);
}
}
}else if(schema.getType().equals("boolean")) {
bool = getBoolean("default", node, false, location, result);
Expand Down Expand Up @@ -2359,6 +2378,121 @@ public Schema getSchema(ObjectNode node, String location, ParseResult result){
}


/**
* Decodes the given string and returns an object applicable to the given schema.
* Throws a ParseException if no applicable object can be recognized.
*/
private Object getDecodedObject( Schema schema, String objectString) throws ParseException {
Object object =
objectString == null?
null :

schema.getClass().equals( DateSchema.class)?
toDate( objectString) :

schema.getClass().equals( DateTimeSchema.class)?
toDateTime( objectString) :

schema.getClass().equals( ByteArraySchema.class)?
toBytes( objectString) :

objectString;

if( object == null && objectString != null) {
throw new ParseException( objectString, 0);
}

return object;
}


/**
* Returns the Date represented by the given RFC3339 date-time string.
* Returns null if this string can't be parsed as Date.
*/
private Date toDateTime( String dateString) {
// Note: For this conversion, regex matching is better than SimpleDateFormat, etc.
// Optional elements (e.g. milliseconds) are not directly handled by SimpleDateFormat.
// Also, SimpleDateFormat is not thread-safe.
Matcher matcher = RFC3339_DATE_TIME_PATTERN.matcher( dateString);

Date dateTime = null;
if( matcher.matches()) {
try {
String year = matcher.group(1);
String month = matcher.group(2);
String day = matcher.group(3);
String hour = matcher.group(4);
String min = matcher.group(5);
String sec = matcher.group(6);
String ms = matcher.group(7);
String zone = matcher.group(10);

Calendar calendar = Calendar.getInstance( TimeZone.getTimeZone( zone == null? "GMT" : "GMT" + zone));
calendar.set( YEAR, Integer.parseInt( year));
calendar.set( MONTH, Integer.parseInt( month) - 1);
calendar.set( DAY_OF_MONTH, Integer.parseInt( day));
calendar.set( HOUR_OF_DAY, Integer.parseInt( hour));
calendar.set( MINUTE, Integer.parseInt( min));
calendar.set( SECOND, Integer.parseInt( sec));
calendar.set( MILLISECOND, ms == null? 0 : (int) (Double.parseDouble( ms) * 1000));

dateTime = calendar.getTime();
}
catch( Exception ignore) {
}
}

return dateTime;
}


/**
* Returns the Date represented by the given RFC3339 full-date string.
* Returns null if this string can't be parsed as Date.
*/
private Date toDate( String dateString) {
Matcher matcher = RFC3339_DATE_PATTERN.matcher( dateString);

Date date = null;
if( matcher.matches()) {
String year = matcher.group(1);
String month = matcher.group(2);
String day = matcher.group(3);

try {
date=
new Calendar.Builder()
.setDate( Integer.parseInt( year), Integer.parseInt( month) - 1, Integer.parseInt( day))
.build()
.getTime();
}
catch( Exception ignore) {
}
}

return date;
}


/**
* Returns the byte array represented by the given base64-encoded string.
* Returns null if this string is not a valid base64 encoding.
*/
private byte[] toBytes( String byteString) {
byte[] bytes;

try {
bytes = Base64.getDecoder().decode( byteString);
}
catch( Exception e) {
bytes = null;
}

return bytes;
}




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

0 comments on commit fdad4e4

Please sign in to comment.