diff --git a/.classpath b/.classpath
deleted file mode 100644
index 746962e..0000000
--- a/.classpath
+++ /dev/null
@@ -1,35 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/.gitignore b/.gitignore
index 9ec8e66..52c2b82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -22,3 +22,8 @@
hs_err_pid*
/target/
/repository/
+
+# IDE files
+/.project
+/.classpath
+/.settings/
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index dcd6357..0000000
--- a/.project
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
- Akiwrapper
-
-
-
-
-
- org.eclipse.jdt.core.javabuilder
-
-
-
-
- org.eclipse.wst.validation.validationbuilder
-
-
-
-
- org.eclipse.m2e.core.maven2Builder
-
-
-
-
-
- org.eclipse.m2e.core.maven2Nature
- org.eclipse.jdt.core.javanature
-
-
diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs
deleted file mode 100644
index cdfe4f1..0000000
--- a/.settings/org.eclipse.core.resources.prefs
+++ /dev/null
@@ -1,5 +0,0 @@
-eclipse.preferences.version=1
-encoding//src/main/java=UTF-8
-encoding//src/test/java=UTF-8
-encoding//src/test/resources=UTF-8
-encoding/=UTF-8
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
deleted file mode 100644
index 76e3512..0000000
--- a/.settings/org.eclipse.jdt.core.prefs
+++ /dev/null
@@ -1,133 +0,0 @@
-eclipse.preferences.version=1
-org.eclipse.jdt.core.builder.annotationPath.allLocations=disabled
-org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
-org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
-org.eclipse.jdt.core.compiler.annotation.nonnull=javax.annotation.Nonnull
-org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=,edu.umd.cs.findbugs.annotations.NonNull,org.eclipse.jdt.annotation.NonNull
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
-org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
-org.eclipse.jdt.core.compiler.annotation.nullable=javax.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullable.secondary=,edu.umd.cs.findbugs.annotations.Nullable,org.eclipse.jdt.annotation.Nullable
-org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled
-org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=11
-org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=11
-org.eclipse.jdt.core.compiler.debug.lineNumber=generate
-org.eclipse.jdt.core.compiler.debug.localVariable=generate
-org.eclipse.jdt.core.compiler.debug.sourceFile=generate
-org.eclipse.jdt.core.compiler.doc.comment.support=enabled
-org.eclipse.jdt.core.compiler.problem.APILeak=warning
-org.eclipse.jdt.core.compiler.problem.annotatedTypeArgumentToUnannotated=info
-org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
-org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
-org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
-org.eclipse.jdt.core.compiler.problem.deadCode=warning
-org.eclipse.jdt.core.compiler.problem.deprecation=warning
-org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled
-org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled
-org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
-org.eclipse.jdt.core.compiler.problem.emptyStatement=info
-org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
-org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=info
-org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
-org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
-org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
-org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
-org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
-org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
-org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
-org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled
-org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
-org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
-org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=info
-org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error
-org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
-org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
-org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
-org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
-org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
-org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
-org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
-org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=info
-org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
-org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
-org.eclipse.jdt.core.compiler.problem.missingJavadocComments=info
-org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
-org.eclipse.jdt.core.compiler.problem.missingJavadocTagDescription=return_tag
-org.eclipse.jdt.core.compiler.problem.missingJavadocTags=info
-org.eclipse.jdt.core.compiler.problem.missingJavadocTagsMethodTypeParameters=disabled
-org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=public
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=info
-org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
-org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
-org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=warning
-org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
-org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
-org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
-org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
-org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
-org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
-org.eclipse.jdt.core.compiler.problem.nullReference=error
-org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
-org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
-org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
-org.eclipse.jdt.core.compiler.problem.parameterAssignment=info
-org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
-org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
-org.eclipse.jdt.core.compiler.problem.potentialNullReference=error
-org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning
-org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
-org.eclipse.jdt.core.compiler.problem.redundantNullCheck=error
-org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=info
-org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=info
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
-org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=info
-org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=warning
-org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
-org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
-org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
-org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
-org.eclipse.jdt.core.compiler.problem.suppressWarningsNotFullyAnalysed=info
-org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled
-org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning
-org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
-org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
-org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled
-org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
-org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
-org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
-org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=error
-org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
-org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=error
-org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
-org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=info
-org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=info
-org.eclipse.jdt.core.compiler.problem.unstableAutoModuleName=warning
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=info
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=disabled
-org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
-org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
-org.eclipse.jdt.core.compiler.problem.unusedImport=info
-org.eclipse.jdt.core.compiler.problem.unusedLabel=info
-org.eclipse.jdt.core.compiler.problem.unusedLocal=info
-org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
-org.eclipse.jdt.core.compiler.problem.unusedParameter=info
-org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
-org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
-org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=info
-org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=info
-org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
-org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
-org.eclipse.jdt.core.compiler.release=disabled
-org.eclipse.jdt.core.compiler.source=11
-org.eclipse.objectteams.otdt.compiler.option.pure_java=enabled
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
deleted file mode 100644
index f897a7f..0000000
--- a/.settings/org.eclipse.m2e.core.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-activeProfiles=
-eclipse.preferences.version=1
-resolveWorkspaceProjects=true
-version=1
diff --git a/.settings/org.sonarlint.eclipse.core.prefs b/.settings/org.sonarlint.eclipse.core.prefs
deleted file mode 100644
index 55537ed..0000000
--- a/.settings/org.sonarlint.eclipse.core.prefs
+++ /dev/null
@@ -1,4 +0,0 @@
-autoEnabled=true
-eclipse.preferences.version=1
-extraProperties=
-fileExclusions=DIRECTORY\:target\r\nGLOB\:src/main/java/com/markozajc/akiwrapper/listbuilder/*.*\r\nDIRECTORY\:example
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index c0327db..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,18 +0,0 @@
-language: java
-jdk:
- - openjdk11
-os: linux
-arch:
- - arm64
- - ppc64le
- - s390x
-script: mvn clean verify -Dmaven.javadoc.skip=true
-dist: xenial
-cache:
- directories:
- - "$HOME/.m2/repository"
- - "$HOME/apache-maven-3.8.1"
-before_install:
-- export M2_HOME=$HOME/apache-maven-3.8.1
-- if [ ! -d $M2_HOME/bin ]; then curl https://archive.apache.org/dist/maven/maven-3/3.8.1/binaries/apache-maven-3.8.1-bin.tar.gz | tar zxf - -C $HOME; fi
-- export PATH=$M2_HOME/bin:$PATH
diff --git a/pom.xml b/pom.xml
index 2081446..9b50ef3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
com.github.markozajc
akiwrapper
- 1.5.2
+ 1.5.2-2
Akiwrapper
A Java API wrapper for Akinator
@@ -35,8 +35,8 @@
UTF-8
UTF-8
- 5.8.2
- 1.7.36
+ 5.9.3
+ 2.0.7
11
11
@@ -47,7 +47,7 @@
com.jcabi
jcabi-xml
- 0.23.2
+ 0.27.2
@@ -61,7 +61,7 @@
com.konghq
unirest-java
- 3.13.8
+ 3.14.2
@@ -101,7 +101,7 @@
com.github.spotbugs
spotbugs-annotations
- 4.6.0
+ 4.7.3
provided
true
@@ -119,6 +119,28 @@
+
+
+ org.apache.maven.plugins
+ maven-enforcer-plugin
+ 3.1.0
+
+
+ enforce-maven
+
+ enforce
+
+
+
+
+ 3.2.5
+
+
+
+
+
+
+
maven-javadoc-plugin
@@ -154,7 +176,7 @@
org.codehaus.mojo
versions-maven-plugin
- 2.10.0
+ 2.11.0
file://${project.basedir}/versions-ruleset.xml
@@ -218,4 +240,4 @@
-
\ No newline at end of file
+
diff --git a/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java b/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java
index d11fe05..e13b31a 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/AkiwrapperBuilder.java
@@ -32,15 +32,11 @@ public class AkiwrapperBuilder {
private static final Logger LOG = LoggerFactory.getLogger(AkiwrapperBuilder.class);
- @Nullable
- private UnirestInstance unirest;
- @Nullable
- private Server server;
+ @Nullable private UnirestInstance unirest;
+ @Nullable private Server server;
private boolean filterProfanity;
- @Nonnull
- private Language language;
- @Nonnull
- private GuessType guessType;
+ @Nonnull private Language language;
+ @Nonnull private GuessType guessType;
/**
* The default profanity filter preference for new {@link Akiwrapper} instances.
@@ -50,14 +46,12 @@ public class AkiwrapperBuilder {
/**
* The default {@link Language} for new {@link Akiwrapper} instances.
*/
- @Nonnull
- public static final Language DEFAULT_LOCALIZATION = ENGLISH;
+ @Nonnull public static final Language DEFAULT_LOCALIZATION = ENGLISH;
/**
* The default {@link GuessType} for new {@link Akiwrapper} instances.
*/
- @Nonnull
- public static final GuessType DEFAULT_GUESS_TYPE = CHARACTER;
+ @Nonnull public static final GuessType DEFAULT_GUESS_TYPE = CHARACTER;
private AkiwrapperBuilder(@Nullable UnirestInstance unirest, @Nullable Server server, boolean filterProfanity,
@Nonnull Language language, @Nonnull GuessType guessType) {
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/Route.java b/src/main/java/com/github/markozajc/akiwrapper/core/Route.java
index 5b64def..309e297 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/Route.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/Route.java
@@ -34,8 +34,7 @@ public final class Route {
* to false may result in unpredicted exceptions! You usually don't need to alter
* this value
*/
- @SuppressFBWarnings("MS_SHOULD_BE_FINAL")
- public static boolean defaultRunChecks = true; // NOSONAR
+ @SuppressFBWarnings("MS_SHOULD_BE_FINAL") public static boolean defaultRunChecks = true; // NOSONAR
/**
* Creates a new session for further gameplay.
@@ -81,10 +80,8 @@ public final class Route {
*/
public static final Route LIST = new Route(1, "/list?mode_question=0&step=%s");
- @Nonnull
- private final String path;
- @Nonnull
- private final String[] filterArguments;
+ @Nonnull private final String path;
+ @Nonnull private final String[] filterArguments;
private final int parametersQuantity;
@@ -182,10 +179,8 @@ public static class Request {
private static final Logger LOG = LoggerFactory.getLogger(Route.Request.class);
- @Nonnull
- private final UnirestInstance unirest;
- @Nonnull
- private final String url;
+ @Nonnull private final UnirestInstance unirest;
+ @Nonnull private final String url;
private final int jQueryCallbackLength;
Request(@Nonnull UnirestInstance unirest, @Nonnull String url, int jQueryCallbackLength) {
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java
index d7af25e..5447ab4 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ApiKey.java
@@ -24,10 +24,8 @@ public class ApiKey {
private static final String FORMAT = "frontaddr=%s&uid_ext_session=%s";
- @Nonnull
- private final String sessionUid;
- @Nonnull
- private final String frontAddress;
+ @Nonnull private final String sessionUid;
+ @Nonnull private final String frontAddress;
ApiKey(@Nonnull String sessionUid, @Nonnull String frontAddress) {
this.sessionUid = sessionUid;
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java
index d6a9012..f2afa77 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/GuessImpl.java
@@ -13,16 +13,11 @@
public class GuessImpl implements Guess {
- @Nonnull
- private final String id;
- @Nonnull
- private final String name;
- @Nullable
- private final String description;
- @Nullable
- private final URL image;
- @Nonnegative
- private final double probability;
+ @Nonnull private final String id;
+ @Nonnull private final String name;
+ @Nullable private final String description;
+ @Nullable private final URL image;
+ @Nonnegative private final double probability;
public GuessImpl(@Nonnull String id, @Nonnull String name, @Nullable String description, @Nullable URL image,
@Nonnegative double probability) {
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java
index abea006..c5b77cf 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/QuestionImpl.java
@@ -14,16 +14,11 @@ public class QuestionImpl implements Question {
private static final String REASON_OUT_OF_QUESTIONS = "no question";
- @Nonnull
- private final String id;
- @Nonnull
- private final String question;
- @Nonnegative
- private final int step;
- @Nonnegative
- private final double gain;
- @Nonnegative
- private final double progression;
+ @Nonnull private final String id;
+ @Nonnull private final String question;
+ @Nonnegative private final int step;
+ @Nonnegative private final double gain;
+ @Nonnegative private final double progression;
public QuestionImpl(@Nonnull String id, @Nonnull String question, @Nonnegative int step, @Nonnegative double gain,
@Nonnegative double progression, @Nonnull Status status) {
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java
index 3354706..7af6db8 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerImpl.java
@@ -13,12 +13,9 @@ public class ServerImpl implements Server {
private static final String LANGUAGE_ID_XPATH = "LANGUAGE/LANG_ID/text()"; // NOSONAR not a URL
private static final String SUBJECT_ID_XPATH = "SUBJECT/SUBJ_ID/text()"; // NOSONAR not a URL
private static final String CANDIDATE_URLS_XPATH = "CANDIDATS/*/text()"; // sic
- @Nonnull
- private final String url;
- @Nonnull
- private final Language localization;
- @Nonnull
- private final GuessType guessType;
+ @Nonnull private final String url;
+ @Nonnull private final Language localization;
+ @Nonnull private final GuessType guessType;
public ServerImpl(@Nonnull String url, @Nonnull Language localization, @Nonnull GuessType guessType) {
this.url = url;
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java
index cd4f540..2a3114c 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/ServerListImpl.java
@@ -10,10 +10,8 @@
public class ServerListImpl implements ServerList {
- @Nonnull
- private Server currentServer;
- @Nonnull
- private final Queue candidateServers;
+ @Nonnull private Server currentServer;
+ @Nonnull private final Queue candidateServers;
@SuppressWarnings("null")
public ServerListImpl(@Nonnull Server first, @Nonnull Server... candidates) {
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java
index 0f3e520..b3c2381 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/entities/impl/immutable/StatusImpl.java
@@ -15,10 +15,8 @@ public class StatusImpl implements Status {
public static final StatusImpl STATUS_OK = new StatusImpl(Level.OK, null);
- @Nullable
- private final String reason;
- @Nonnull
- private final Level level;
+ @Nullable private final String reason;
+ @Nonnull private final Level level;
private StatusImpl(@Nonnull Level level, @Nullable String reason) {
this.level = level;
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java b/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java
index 6c85422..7609cdb 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/impl/AkiwrapperImpl.java
@@ -54,17 +54,12 @@ public String querystring() {
}
}
- @Nonnull
- private final Server server;
- @Nonnull
- private final UnirestInstance unirest;
+ @Nonnull private final Server server;
+ @Nonnull private final UnirestInstance unirest;
private final boolean filterProfanity;
- @Nonnull
- private final Session session;
- @Nonnegative
- private int currentStep;
- @Nullable
- private Question question;
+ @Nonnull private final Session session;
+ @Nonnegative private int currentStep;
+ @Nullable private Question question;
private List guessCache;
@SuppressWarnings("null")
@@ -115,7 +110,7 @@ public Question undoAnswer() {
this.guessCache = null;
Question current = getQuestion();
- if ((current == null) || (current.getStep() < 1))
+ if (current == null || current.getStep() < 1)
return null;
var questionJson = CANCEL_ANSWER
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java b/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java
index fb8d8c4..6f74a9b 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/utils/Servers.java
@@ -24,9 +24,8 @@
@SuppressFBWarnings("REC_CATCH_EXCEPTION")
public final class Servers {
- private static final String FOOTPRINT = "cd8e6509f3420878e18d75b9831b317f";
private static final String LIST_URL =
- "https://global3.akinator.com/ws/instances_v2.php?media_id=14" + "&mode=https&footprint=" + FOOTPRINT;
+ "https://global3.akinator.com/ws/instances_v2.php?media_id=14&mode=https&footprint=cd8e6509f3420878e18d75b9831b317f";
private Servers() {}
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java b/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java
index f361249..f418cb9 100644
--- a/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/utils/UnirestUtils.java
@@ -1,5 +1,6 @@
package com.github.markozajc.akiwrapper.core.utils;
+import static com.github.markozajc.akiwrapper.core.utils.WorkaroundUtils.workaroundIncompleteChain;
import static kong.unirest.Unirest.spawnInstance;
import javax.annotation.Nonnull;
@@ -50,7 +51,9 @@ public static synchronized void shutdownInstance() {
* Configures a new {@link UnirestInstance} for use by Akiwrapper. Akinator's API
* servers are quite picky about the headers you send to them so if you supply
* {@link AkiwrapperBuilder} with your own {@link UnirestInstance} you should either
- * pass it through this or configure it accordingly yourself.
+ * pass it through this or configure it accordingly yourself. This also applies the
+ * workaround to Akinator's incomplete SSL chain from
+ * {@link WorkaroundUtils#workaroundIncompleteChain(kong.unirest.Config)} .
* Note: even though this method returns a {@link UnirestInstance}, the instance you
* pass to it is itself mutated and returned. The return value is only there for ease
* of chaining.
@@ -61,6 +64,7 @@ public static synchronized void shutdownInstance() {
* @return the {@link UnirestInstance} you passed, used for chaining
*/
@Nonnull
+ @SuppressWarnings("null")
public static UnirestInstance configureInstance(@Nonnull UnirestInstance unirest) {
unirest.config()
.addDefaultHeader("Accept",
@@ -76,6 +80,8 @@ public static UnirestInstance configureInstance(@Nonnull UnirestInstance unirest
"(KHTML, like Gecko) Chrome/81.0.4044.92 Safari/537.36")
.addDefaultHeader("Referer", "https://en.akinator.com/game")
.cookieSpec("ignore");
+ workaroundIncompleteChain(unirest.config());
+
return unirest;
}
diff --git a/src/main/java/com/github/markozajc/akiwrapper/core/utils/WorkaroundUtils.java b/src/main/java/com/github/markozajc/akiwrapper/core/utils/WorkaroundUtils.java
new file mode 100644
index 0000000..0cc1427
--- /dev/null
+++ b/src/main/java/com/github/markozajc/akiwrapper/core/utils/WorkaroundUtils.java
@@ -0,0 +1,149 @@
+package com.github.markozajc.akiwrapper.core.utils;
+
+import static java.util.Arrays.stream;
+
+import java.io.IOException;
+import java.security.*;
+import java.security.cert.*;
+
+import javax.annotation.Nonnull;
+import javax.net.ssl.*;
+
+import kong.unirest.Config;
+
+/**
+ * A utility class with workarounds for problems with Akinator's infrastructure.
+ *
+ * @author Marko Zajc
+ */
+public class WorkaroundUtils {
+
+ /**
+ * Applies a workaround for the {@code PKIX path building failed} exception to a
+ * Unirest {@link Config}.
+ * Note: even though this method returns a {@link Config}, the instance you pass to
+ * it is itself mutated and returned. The return value is only there for ease of
+ * chaining.
+ *
+ * @param config
+ * the {@link Config} to apply the workaround to
+ *
+ * @return the {@link Config} for chaining
+ *
+ * @implNote it seems that Akinator sysadmins have misconfigured the en.akinator.com
+ * server such that it fails to send the intermediate SSL certificate.
+ * Because we only trust the root certificate, the local certificate chain
+ * resolution fails and an exception is thrown. This workaround manually
+ * trusts the intermediate certificate such that the resolution succeeds
+ * without having to completely disable certificate validation. You can get
+ * the modified {@link SSLContext} to apply yourself with
+ * {@link #getIncompleteChainWorkaroundSSLContext()} or if you're using
+ * your own {@link SSLContext} and you want to add the
+ * {@link TrustManager}, you can get it from
+ * {@link #getIncompleteChainWorkaroundCustomTrustManager()}.
+ */
+ @Nonnull
+ @SuppressWarnings("null")
+ public static Config workaroundIncompleteChain(@Nonnull Config config) {
+ return config.sslContext(getIncompleteChainWorkaroundSSLContext());
+ }
+
+ /**
+ * @return the {@link SSLContext} used to workaround the
+ * {@code PKIX path building failed} exception.
+ *
+ * @see #workaroundIncompleteChain(Config)
+ */
+ @Nonnull
+ public static SSLContext getIncompleteChainWorkaroundSSLContext() {
+ try {
+ var defaultTrust = getDefaultTrustManager();
+ var customTrust = getIncompleteChainWorkaroundCustomTrustManager();
+ var combinedTrust = getCombinedTrust(defaultTrust, customTrust);
+
+ var sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, new TrustManager[] { combinedTrust }, null);
+ return sslContext;
+ } catch (GeneralSecurityException | IOException e) {
+ throw new RuntimeException("Could not create a workaround SSLContext", e);
+ }
+ }
+
+ @Nonnull
+ private static X509TrustManager getCombinedTrust(@Nonnull X509TrustManager defaultTrust,
+ @Nonnull X509TrustManager customTrust) {
+ return new X509TrustManager() {
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ // merging isn't necessary
+ return defaultTrust.getAcceptedIssuers();
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ try {
+ defaultTrust.checkServerTrusted(chain, authType);
+ } catch (CertificateException e) {
+ customTrust.checkServerTrusted(chain, authType);
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ // merging isn't necessary
+ defaultTrust.checkClientTrusted(chain, authType);
+ }
+ };
+ }
+
+ /**
+ * @return the {@link X509TrustManager} used to workaround the
+ * {@code PKIX path building failed} exception.
+ *
+ * @throws KeyStoreException
+ * @throws IOException
+ * @throws NoSuchAlgorithmException
+ * @throws CertificateException
+ *
+ * @see #workaroundIncompleteChain(Config)
+ */
+ @Nonnull
+ @SuppressWarnings("null")
+ public static X509TrustManager getIncompleteChainWorkaroundCustomTrustManager() throws KeyStoreException,
+ IOException,
+ NoSuchAlgorithmException,
+ CertificateException {
+ KeyStore store;
+ try (var is = WorkaroundUtils.class.getResourceAsStream("/intermediate.jks")) {
+ store = KeyStore.getInstance(KeyStore.getDefaultType());
+ store.load(is, "thingamabob".toCharArray()); // NOSONAR not a secure credential
+ }
+
+ if (store.size() != 1)
+ throw new IOException("The intermediate keystore does not contain exactly one entry (did loading fail?)");
+
+ var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(store);
+
+ return stream(tmf.getTrustManagers()).filter(X509TrustManager.class::isInstance)
+ .map(X509TrustManager.class::cast)
+ .findAny()
+ .orElseThrow();
+ }
+
+ @Nonnull
+ @SuppressWarnings("null")
+ private static X509TrustManager getDefaultTrustManager() throws NoSuchAlgorithmException, KeyStoreException {
+ var tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+
+ return stream(tmf.getTrustManagers()).filter(X509TrustManager.class::isInstance)
+ .map(X509TrustManager.class::cast)
+ .findAny()
+ .orElseThrow();
+ }
+
+ private WorkaroundUtils() {}
+
+}
diff --git a/src/main/resources/intermediate.jks b/src/main/resources/intermediate.jks
new file mode 100644
index 0000000..b29b21b
Binary files /dev/null and b/src/main/resources/intermediate.jks differ
diff --git a/src/main/resources/intermediate.jks.txt b/src/main/resources/intermediate.jks.txt
new file mode 100644
index 0000000..a272934
--- /dev/null
+++ b/src/main/resources/intermediate.jks.txt
@@ -0,0 +1,2 @@
+This keystore contains the intermediate "Go Daddy Secure Certificate Authority - G2" key used by Akinator's server (because they're too incompetent to send it)
+Password: thingamabob (because JKS requires a password)
diff --git a/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java b/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java
index 5c09f6d..0bd9ec9 100644
--- a/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java
+++ b/src/test/java/com/github/markozajc/akiwrapper/IntegrationTest.java
@@ -1,6 +1,7 @@
package com.github.markozajc.akiwrapper;
import static java.lang.String.format;
+import static org.junit.jupiter.api.Assumptions.abort;
import static org.slf4j.LoggerFactory.getLogger;
import java.util.List;
@@ -41,8 +42,7 @@ void testAkiwrapper(@Nonnull Language language, @Nonnull GuessType guessType) {
try {
api = new AkiwrapperBuilder().setLanguage(language).setGuessType(guessType).build();
} catch (ServerNotFoundException e) {
- log.warn("Current combination not supported, server wasn't found.");
- log.trace("", e);
+ abort("Current combination not supported, server wasn't found.");
return;
}