Skip to content

Commit 54e2574

Browse files
[Java][Jersey2] Fix typo and script, Log enhancements, HTTP signature, deserialization (#6476)
* Mustache template should use invokerPackage tag to generate import * fix typo, fix script issue, add log statement for troubleshooting * Add java jersey2 samples with OpenAPI doc that has HTTP signature security scheme * Add sample for Java jersey2 and HTTP signature scheme * Add unit test for oneOf schema deserialization * Add unit test for oneOf schema deserialization * Add log statements * Add profile for jersey2 * Temporarily disable unit test * Temporarily disable unit test * fix typo in pom.xml * fix duplicate jersey2 samples * fix duplicate jersey2 samples * fix duplicate artifact id * fix duplicate jersey2 samples * run samples scripts
1 parent 7e5f720 commit 54e2574

File tree

304 files changed

+32362
-7
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

304 files changed

+32362
-7
lines changed
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package org.openapitools.client;
2+
3+
import org.openapitools.client.model.Mammal;
4+
import org.openapitools.client.model.AppleReq;
5+
import org.openapitools.client.model.BananaReq;
6+
import org.openapitools.client.model.FruitReq;
7+
import org.openapitools.client.model.BasquePig;
8+
import org.openapitools.client.model.Pig;
9+
import org.openapitools.client.model.Whale;
10+
import org.openapitools.client.model.Zebra;
11+
import java.lang.Exception;
12+
13+
import org.junit.*;
14+
import static org.junit.Assert.*;
15+
16+
17+
public class JSONComposedSchemaTest {
18+
JSON json = null;
19+
Mammal mammal = null;
20+
21+
@Before
22+
public void setup() {
23+
json = new JSON();
24+
mammal = new Mammal();
25+
}
26+
27+
/**
28+
* Validate a oneOf schema can be deserialized into the expected class.
29+
* The oneOf schema does not have a discriminator.
30+
*/
31+
@Test
32+
public void testOneOfSchemaWithoutDiscriminator() throws Exception {
33+
// BananaReq and AppleReq have explicitly defined properties that are different by name.
34+
// There is no discriminator property.
35+
String str = "{ \"cultivar\": \"golden delicious\", \"mealy\": false }";
36+
FruitReq o = json.getContext(null).readValue(str, FruitReq.class);
37+
assertTrue(o.getActualInstance() instanceof AppleReq);
38+
}
39+
40+
/**
41+
* Validate a oneOf schema can be deserialized into the expected class.
42+
* The oneOf schema has a discriminator.
43+
*/
44+
@Test
45+
public void testOneOfSchemaWithDiscriminator() throws Exception {
46+
// Mammal can be one of whale, pig and zebra.
47+
// pig has sub-classes.
48+
String str = "{ \"className\": \"whale\", \"hasBaleen\": true, \"hasTeeth\": false }";
49+
/*
50+
DISABLING unit test for now until ambiguity of discriminator is resolved.
51+
52+
// Note that the 'zebra' schema does not have any explicit property defined AND
53+
// it has additionalProperties: true. Hence without a discriminator the above
54+
// JSON payload would match both 'whale' and 'zebra'. This is because the 'hasBaleen'
55+
// and 'hasTeeth' would be considered additional (undeclared) properties for 'zebra'.
56+
Mammal o = json.getContext(null).readValue(str, Mammal.class);
57+
assertTrue(o.getActualInstance() instanceof Whale);
58+
59+
str = "{ \"className\": \"zebra\" }";
60+
o = json.getContext(null).readValue(str, Mammal.class);
61+
assertTrue(o.getActualInstance() instanceof Zebra);
62+
63+
str = "{ \"className\": \"BasquePig\" }";
64+
o = json.getContext(null).readValue(str, Mammal.class);
65+
assertTrue(o.getActualInstance() instanceof BasquePig);
66+
*/
67+
}
68+
}

bin/java-petstore-jersey2-java8.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ find samples/client/petstore/java/jersey2-java8 -maxdepth 1 -type f ! -name "REA
3535
java $JAVA_OPTS -jar $executable $ags
3636

3737
# copy additional manually written unit-tests
38-
mkdir samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client
39-
mkdir samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/auth
40-
mkdir samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/model
38+
mkdir -p samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client
39+
mkdir -p samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/auth
40+
mkdir -p samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/model
4141

4242
cp CI/samples.ci/client/petstore/java/test-manual/common/StringUtilTest.java samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/StringUtilTest.java
4343
cp CI/samples.ci/client/petstore/java/test-manual/jersey2/ApiClientTest.java samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/ApiClientTest.java
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"library": "jersey2",
3+
"artifactId": "petstore-openapi3-jersey2-java8",
4+
"dateLibrary": "java8"
5+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
#!/bin/sh
2+
3+
SCRIPT="$0"
4+
echo "# START SCRIPT: $SCRIPT"
5+
6+
while [ -h "$SCRIPT" ] ; do
7+
ls=`ls -ld "$SCRIPT"`
8+
link=`expr "$ls" : '.*-> \(.*\)$'`
9+
if expr "$link" : '/.*' > /dev/null; then
10+
SCRIPT="$link"
11+
else
12+
SCRIPT=`dirname "$SCRIPT"`/"$link"
13+
fi
14+
done
15+
16+
if [ ! -d "${APP_DIR}" ]; then
17+
APP_DIR=`dirname "$SCRIPT"`/..
18+
APP_DIR=`cd "${APP_DIR}"; pwd`
19+
fi
20+
21+
executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar"
22+
23+
if [ ! -f "$executable" ]
24+
then
25+
mvn -B clean package
26+
fi
27+
28+
# if you've executed sbt assembly previously it will use that instead.
29+
export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties"
30+
yaml="modules/openapi-generator/src/test/resources/3_0/python-experimental/petstore-with-fake-endpoints-models-for-testing-with-http-signature.yaml"
31+
ags="generate --artifact-id petstore-openapi3-jersey2-java8 -i $yaml -g java -c bin/openapi3/java-petstore-jersey2-java8.json -o samples/openapi3/client/petstore/java/jersey2-java8 --additional-properties hideGenerationTimestamp=true --additional-properties serverPort=8082 $@"
32+
33+
echo "Removing files and folders under samples/openapi3/client/petstore/java/jersey2-java8/src/main"
34+
rm -rf samples/openapi3/client/petstore/java/jersey2-java8/src/main
35+
find samples/openapi3/client/petstore/java/jersey2-java8 -maxdepth 1 -type f ! -name "README.md" -exec rm {} +
36+
java $JAVA_OPTS -jar $executable $ags
37+
38+
# copy additional manually written unit-tests
39+
mkdir -p samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client
40+
mkdir -p samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/auth
41+
mkdir -p samples/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/model
42+
43+
cp CI/samples.ci/client/petstore/java/test-manual/jersey2-java8/JSONTest.java samples/openapi3/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/JSONTest.java
44+
cp CI/samples.ci/client/petstore/java/test-manual/jersey2-java8/JSONComposedSchemaTest.java samples/openapi3/client/petstore/java/jersey2-java8/src/test/java/org/openapitools/client/JSONComposedSchemaTest.java

bin/utils/ensure-up-to-date

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ declare -a samples=(
4040
"${root}/bin/python-server-all.sh"
4141
"${root}/bin/openapi3/python-petstore.sh"
4242
"${root}/bin/openapi3/python-experimental-petstore.sh"
43+
"${root}/bin/openapi3/java-petstore-jersey2-java8.sh"
4344
"${root}/bin/php-petstore.sh"
4445
"${root}/bin/php-silex-petstore-server.sh"
4546
"${root}/bin/php-symfony-petstore.sh"

modules/openapi-generator/src/main/resources/Java/libraries/jersey2/ApiClient.mustache

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import org.glassfish.jersey.logging.LoggingFeature;
3636
import org.apache.commons.io.FileUtils;
3737
import org.glassfish.jersey.filter.LoggingFilter;
3838
{{/supportJava6}}
39+
import java.util.logging.Level;
40+
import java.util.logging.Logger;
3941
import java.util.Collection;
4042
import java.util.Collections;
4143
import java.util.Map;
@@ -73,6 +75,8 @@ public class ApiClient {
7375
protected Map<String, String> defaultHeaderMap = new HashMap<String, String>();
7476
protected Map<String, String> defaultCookieMap = new HashMap<String, String>();
7577
protected String basePath = "{{{basePath}}}";
78+
private static final Logger log = Logger.getLogger(ApiClient.class.getName());
79+
7680
protected List<ServerConfiguration> servers = new ArrayList<ServerConfiguration>({{#servers}}{{#-first}}Arrays.asList(
7781
{{/-first}} new ServerConfiguration(
7882
"{{{url}}}",
@@ -928,6 +932,9 @@ public class ApiClient {
928932
}
929933
} catch (Exception ex) {
930934
// failed to deserialize, do nothing and try next one (schema)
935+
// Logging the error may be useful to troubleshoot why a payload fails to match
936+
// the schema.
937+
log.log(Level.FINE, "Input data does not match schema '" + schemaName + "'", ex);
931938
}
932939
} else {// unknown type
933940
throw new ApiException(schemaType.getClass() + " is not a GenericType and cannot be handled properly in deserialization.");
@@ -938,7 +945,7 @@ public class ApiClient {
938945
if (matchCounter > 1 && "oneOf".equals(schema.getSchemaType())) {// more than 1 match for oneOf
939946
throw new ApiException("Response body is invalid as it matches more than one schema (" + StringUtil.join(matchSchemas, ", ") + ") defined in the oneOf model: " + schema.getClass().getName());
940947
} else if (matchCounter == 0) { // fail to match any in oneOf/anyOf schemas
941-
throw new ApiException("Response body is invalid as it doens't match any schemas (" + StringUtil.join(schema.getSchemas().keySet(), ", ") + ") defined in the oneOf/anyOf model: " + schema.getClass().getName());
948+
throw new ApiException("Response body is invalid as it does not match any schemas (" + StringUtil.join(schema.getSchemas().keySet(), ", ") + ") defined in the oneOf/anyOf model: " + schema.getClass().getName());
942949
} else { // only one matched
943950
schema.setActualInstance(result);
944951
return schema;

modules/openapi-generator/src/main/resources/Java/libraries/jersey2/anyof_model.mustache

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import javax.ws.rs.core.GenericType;
22
import javax.ws.rs.core.Response;
33
import java.io.IOException;
4+
import java.util.logging.Level;
5+
import java.util.logging.Logger;
46
import java.util.ArrayList;
57
import java.util.HashMap;
68
import java.util.Map;
@@ -15,6 +17,8 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
1517
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>xmlAnnotation}}
1618
@JsonDeserialize(using={{classname}}.{{classname}}Deserializer.class)
1719
public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-implements}}, {{{.}}}{{/vendorExtensions.x-implements}} {
20+
private static final Logger log = Logger.getLogger({{classname}}.class.getName());
21+
1822
public static class {{classname}}Deserializer extends StdDeserializer<{{classname}}> {
1923
public {{classname}}Deserializer() {
2024
this({{classname}}.class);
@@ -37,7 +41,8 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
3741
ret.setActualInstance(deserialized);
3842
return ret;
3943
} catch (Exception e) {
40-
// deserialization failed, continue
44+
// deserialization failed, continue, log to help debugging
45+
log.log(Level.FINER, "Input data does not match '{{classname}}'", e);
4146
}
4247

4348
{{/anyOf}}

modules/openapi-generator/src/main/resources/Java/libraries/jersey2/auth/HttpSignatureAuth.mustache

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import java.util.Locale;
1717
import java.util.Map;
1818
import java.util.List;
1919
import java.security.spec.AlgorithmParameterSpec;
20+
import java.security.InvalidKeyException;
2021

2122
import org.tomitribe.auth.signatures.Algorithm;
2223
import org.tomitribe.auth.signatures.Signer;
@@ -204,7 +205,7 @@ public class HttpSignatureAuth implements Authentication {
204205
* @throws InvalidKeyException Unable to parse the key, or the security provider for this key
205206
* is not installed.
206207
*/
207-
public void setPrivateKey(Key key) throws InvalidKeyException {
208+
public void setPrivateKey(Key key) throws InvalidKeyException, ApiException {
208209
if (key == null) {
209210
throw new ApiException("Private key (java.security.Key) cannot be null");
210211
}

modules/openapi-generator/src/main/resources/Java/libraries/jersey2/oneof_model.mustache

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import javax.ws.rs.core.GenericType;
22
import javax.ws.rs.core.Response;
33
import java.io.IOException;
4+
import java.util.logging.Level;
5+
import java.util.logging.Logger;
46
import java.util.ArrayList;
57
import java.util.HashMap;
68
import java.util.Map;
@@ -15,6 +17,8 @@ import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
1517
{{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{>xmlAnnotation}}
1618
@JsonDeserialize(using={{classname}}.{{classname}}Deserializer.class)
1719
public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-implements}}, {{{.}}}{{/vendorExtensions.x-implements}} {
20+
private static final Logger log = Logger.getLogger({{classname}}.class.getName());
21+
1822
public static class {{classname}}Deserializer extends StdDeserializer<{{classname}}> {
1923
public {{classname}}Deserializer() {
2024
this({{classname}}.class);
@@ -35,8 +39,10 @@ public class {{classname}} extends AbstractOpenApiSchema{{#vendorExtensions.x-im
3539
try {
3640
deserialized = tree.traverse(jp.getCodec()).readValueAs({{{.}}}.class);
3741
match++;
42+
log.log(Level.FINER, "Input data matches schema '{{{.}}}'");
3843
} catch (Exception e) {
3944
// deserialization failed, continue
45+
log.log(Level.FINER, "Input data does not match schema '{{{.}}}'", e);
4046
}
4147

4248
{{/oneOf}}

pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,18 @@
703703
<module>samples/client/petstore/java/jersey2-java8</module>
704704
</modules>
705705
</profile>
706+
<profile>
707+
<id>java-client-openapi3-jersey2-java8</id>
708+
<activation>
709+
<property>
710+
<name>env</name>
711+
<value>java</value>
712+
</property>
713+
</activation>
714+
<modules>
715+
<module>samples/openapi3/client/petstore/java/jersey2-java8</module>
716+
</modules>
717+
</profile>
706718
<profile>
707719
<id>java-client-okhttp-gson</id>
708720
<activation>
@@ -1252,6 +1264,7 @@
12521264
<module>samples/client/petstore/java/feign10x</module>
12531265
<module>samples/client/petstore/java/jersey1</module>
12541266
<module>samples/client/petstore/java/jersey2-java8</module>
1267+
<module>samples/openapi3/client/petstore/java/jersey2-java8</module>
12551268
<module>samples/client/petstore/java/okhttp-gson</module>
12561269
<module>samples/client/petstore/java/retrofit2</module>
12571270
<module>samples/client/petstore/java/retrofit2rx</module>

samples/client/petstore/java/jersey2-java8/src/main/java/org/openapitools/client/ApiClient.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import java.nio.file.Files;
2929
import java.nio.file.StandardCopyOption;
3030
import org.glassfish.jersey.logging.LoggingFeature;
31+
import java.util.logging.Level;
32+
import java.util.logging.Logger;
3133
import java.util.Collection;
3234
import java.util.Collections;
3335
import java.util.Map;
@@ -60,6 +62,8 @@ public class ApiClient {
6062
protected Map<String, String> defaultHeaderMap = new HashMap<String, String>();
6163
protected Map<String, String> defaultCookieMap = new HashMap<String, String>();
6264
protected String basePath = "http://petstore.swagger.io:80/v2";
65+
private static final Logger log = Logger.getLogger(ApiClient.class.getName());
66+
6367
protected List<ServerConfiguration> servers = new ArrayList<ServerConfiguration>(Arrays.asList(
6468
new ServerConfiguration(
6569
"http://petstore.swagger.io:80/v2",
@@ -845,6 +849,9 @@ public AbstractOpenApiSchema deserializeSchemas(Response response, AbstractOpenA
845849
}
846850
} catch (Exception ex) {
847851
// failed to deserialize, do nothing and try next one (schema)
852+
// Logging the error may be useful to troubleshoot why a payload fails to match
853+
// the schema.
854+
log.log(Level.FINE, "Input data does not match schema '" + schemaName + "'", ex);
848855
}
849856
} else {// unknown type
850857
throw new ApiException(schemaType.getClass() + " is not a GenericType and cannot be handled properly in deserialization.");
@@ -855,7 +862,7 @@ public AbstractOpenApiSchema deserializeSchemas(Response response, AbstractOpenA
855862
if (matchCounter > 1 && "oneOf".equals(schema.getSchemaType())) {// more than 1 match for oneOf
856863
throw new ApiException("Response body is invalid as it matches more than one schema (" + StringUtil.join(matchSchemas, ", ") + ") defined in the oneOf model: " + schema.getClass().getName());
857864
} else if (matchCounter == 0) { // fail to match any in oneOf/anyOf schemas
858-
throw new ApiException("Response body is invalid as it doens't match any schemas (" + StringUtil.join(schema.getSchemas().keySet(), ", ") + ") defined in the oneOf/anyOf model: " + schema.getClass().getName());
865+
throw new ApiException("Response body is invalid as it does not match any schemas (" + StringUtil.join(schema.getSchemas().keySet(), ", ") + ") defined in the oneOf/anyOf model: " + schema.getClass().getName());
859866
} else { // only one matched
860867
schema.setActualInstance(result);
861868
return schema;
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
*.class
2+
3+
# Mobile Tools for Java (J2ME)
4+
.mtj.tmp/
5+
6+
# Package Files #
7+
*.jar
8+
*.war
9+
*.ear
10+
11+
# exclude jar for gradle wrapper
12+
!gradle/wrapper/*.jar
13+
14+
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
15+
hs_err_pid*
16+
17+
# build files
18+
**/target
19+
target
20+
.gradle
21+
build
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# OpenAPI Generator Ignore
2+
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
3+
4+
# Use this file to prevent files from being overwritten by the generator.
5+
# The patterns follow closely to .gitignore or .dockerignore.
6+
7+
# As an example, the C# client generator defines ApiClient.cs.
8+
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
9+
#ApiClient.cs
10+
11+
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
12+
#foo/*/qux
13+
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
14+
15+
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
16+
#foo/**/qux
17+
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
18+
19+
# You can also negate patterns with an exclamation (!).
20+
# For example, you can ignore all files in a docs folder with the file extension .md:
21+
#docs/*.md
22+
# Then explicitly reverse the ignore rule for a single file:
23+
#!docs/README.md

0 commit comments

Comments
 (0)