mirror of https://github.com/shred/acme4j
JSON getters never return null
parent
4b3eb22eef
commit
4de82be5f3
|
@ -64,7 +64,7 @@ public class Account extends AcmeJsonResource {
|
||||||
* {@code null} if the server did not provide such an information.
|
* {@code null} if the server did not provide such an information.
|
||||||
*/
|
*/
|
||||||
public Boolean getTermsOfServiceAgreed() {
|
public Boolean getTermsOfServiceAgreed() {
|
||||||
return getJSON().get(KEY_TOS_AGREED).optional().map(Value::asBoolean).orElse(null);
|
return getJSON().get(KEY_TOS_AGREED).map(Value::asBoolean).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +85,7 @@ public class Account extends AcmeJsonResource {
|
||||||
* {@link Status#REVOKED}.
|
* {@link Status#REVOKED}.
|
||||||
*/
|
*/
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
return getJSON().get(KEY_STATUS).asStatusOrElse(Status.UNKNOWN);
|
return getJSON().get(KEY_STATUS).asStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -50,12 +50,12 @@ public class Authorization extends AcmeJsonResource {
|
||||||
* order, check the {@link #isWildcard()} method.
|
* order, check the {@link #isWildcard()} method.
|
||||||
*/
|
*/
|
||||||
public String getDomain() {
|
public String getDomain() {
|
||||||
JSON jsonIdentifier = getJSON().get("identifier").required().asObject();
|
JSON jsonIdentifier = getJSON().get("identifier").asObject();
|
||||||
String type = jsonIdentifier.get("type").required().asString();
|
String type = jsonIdentifier.get("type").asString();
|
||||||
if (!"dns".equals(type)) {
|
if (!"dns".equals(type)) {
|
||||||
throw new AcmeProtocolException("Unknown authorization type: " + type);
|
throw new AcmeProtocolException("Unknown authorization type: " + type);
|
||||||
}
|
}
|
||||||
return jsonIdentifier.get("value").required().asString();
|
return jsonIdentifier.get("value").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -65,14 +65,14 @@ public class Authorization extends AcmeJsonResource {
|
||||||
* {@link Status#INVALID}, {@link Status#DEACTIVATED}, {@link Status#REVOKED}.
|
* {@link Status#INVALID}, {@link Status#DEACTIVATED}, {@link Status#REVOKED}.
|
||||||
*/
|
*/
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
return getJSON().get("status").asStatusOrElse(Status.UNKNOWN);
|
return getJSON().get("status").asStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the expiry date of the authorization, if set by the server.
|
* Gets the expiry date of the authorization, if set by the server.
|
||||||
*/
|
*/
|
||||||
public Instant getExpires() {
|
public Instant getExpires() {
|
||||||
return getJSON().get("expires").optional()
|
return getJSON().get("expires")
|
||||||
.map(Value::asString)
|
.map(Value::asString)
|
||||||
.map(AcmeUtils::parseTimestamp)
|
.map(AcmeUtils::parseTimestamp)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
@ -83,7 +83,7 @@ public class Authorization extends AcmeJsonResource {
|
||||||
* {@code false} otherwise.
|
* {@code false} otherwise.
|
||||||
*/
|
*/
|
||||||
public boolean isWildcard() {
|
public boolean isWildcard() {
|
||||||
return getJSON().get("wildcard").optional()
|
return getJSON().get("wildcard")
|
||||||
.map(Value::asBoolean)
|
.map(Value::asBoolean)
|
||||||
.orElse(false);
|
.orElse(false);
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class Metadata {
|
||||||
* available.
|
* available.
|
||||||
*/
|
*/
|
||||||
public URI getTermsOfService() {
|
public URI getTermsOfService() {
|
||||||
return meta.get("termsOfService").asURI();
|
return meta.get("termsOfService").map(Value::asURI).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,7 +52,7 @@ public class Metadata {
|
||||||
* server. {@code null} if not available.
|
* server. {@code null} if not available.
|
||||||
*/
|
*/
|
||||||
public URL getWebsite() {
|
public URL getWebsite() {
|
||||||
return meta.get("website").asURL();
|
return meta.get("website").map(Value::asURL).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,7 +60,9 @@ public class Metadata {
|
||||||
* itself for the purposes of CAA record validation. Empty if not available.
|
* itself for the purposes of CAA record validation. Empty if not available.
|
||||||
*/
|
*/
|
||||||
public Collection<String> getCaaIdentities() {
|
public Collection<String> getCaaIdentities() {
|
||||||
return meta.get("caaIdentities").asArray().stream()
|
return meta.get("caaIdentities")
|
||||||
|
.asArray()
|
||||||
|
.stream()
|
||||||
.map(Value::asString)
|
.map(Value::asString)
|
||||||
.collect(toList());
|
.collect(toList());
|
||||||
}
|
}
|
||||||
|
@ -69,7 +71,7 @@ public class Metadata {
|
||||||
* Returns whether an external account is required by this CA.
|
* Returns whether an external account is required by this CA.
|
||||||
*/
|
*/
|
||||||
public boolean isExternalAccountRequired() {
|
public boolean isExternalAccountRequired() {
|
||||||
return meta.get("externalAccountRequired").orElse(false).asBoolean();
|
return meta.get("externalAccountRequired").map(Value::asBoolean).orElse(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -45,21 +45,21 @@ public class Order extends AcmeJsonResource {
|
||||||
* {@link Status#PROCESSING}, {@link Status#VALID}, {@link Status#INVALID}.
|
* {@link Status#PROCESSING}, {@link Status#VALID}, {@link Status#INVALID}.
|
||||||
*/
|
*/
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
return getJSON().get("status").asStatusOrElse(Status.UNKNOWN);
|
return getJSON().get("status").asStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a {@link Problem} document if the order failed.
|
* Returns a {@link Problem} document if the order failed.
|
||||||
*/
|
*/
|
||||||
public Problem getError() {
|
public Problem getError() {
|
||||||
return getJSON().get("error").asProblem(getLocation());
|
return getJSON().get("error").map(v -> v.asProblem(getLocation())).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the expiry date of the authorization, if set by the server.
|
* Gets the expiry date of the authorization, if set by the server.
|
||||||
*/
|
*/
|
||||||
public Instant getExpires() {
|
public Instant getExpires() {
|
||||||
return getJSON().get("expires").asInstant();
|
return getJSON().get("expires").map(Value::asInstant).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,14 +78,14 @@ public class Order extends AcmeJsonResource {
|
||||||
* Gets the "not before" date that was used for the order, or {@code null}.
|
* Gets the "not before" date that was used for the order, or {@code null}.
|
||||||
*/
|
*/
|
||||||
public Instant getNotBefore() {
|
public Instant getNotBefore() {
|
||||||
return getJSON().get("notBefore").asInstant();
|
return getJSON().get("notBefore").map(Value::asInstant).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the "not after" date that was used for the order, or {@code null}.
|
* Gets the "not after" date that was used for the order, or {@code null}.
|
||||||
*/
|
*/
|
||||||
public Instant getNotAfter() {
|
public Instant getNotAfter() {
|
||||||
return getJSON().get("notAfter").asInstant();
|
return getJSON().get("notAfter").map(Value::asInstant).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,7 +114,7 @@ public class Order extends AcmeJsonResource {
|
||||||
* Gets the {@link Certificate} if it is available. {@code null} otherwise.
|
* Gets the {@link Certificate} if it is available. {@code null} otherwise.
|
||||||
*/
|
*/
|
||||||
public Certificate getCertificate() {
|
public Certificate getCertificate() {
|
||||||
return getJSON().get("certificate").optional()
|
return getJSON().get("certificate")
|
||||||
.map(Value::asURL)
|
.map(Value::asURL)
|
||||||
.map(getLogin()::bindCertificate)
|
.map(getLogin()::bindCertificate)
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
||||||
|
|
||||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
import org.shredzone.acme4j.toolbox.JSON;
|
import org.shredzone.acme4j.toolbox.JSON;
|
||||||
|
import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a JSON Problem.
|
* Represents a JSON Problem.
|
||||||
|
@ -53,12 +54,16 @@ public class Problem implements Serializable {
|
||||||
* Returns the problem type. It is always an absolute URI.
|
* Returns the problem type. It is always an absolute URI.
|
||||||
*/
|
*/
|
||||||
public URI getType() {
|
public URI getType() {
|
||||||
|
return problemJson.get("type")
|
||||||
|
.map(Value::asString)
|
||||||
|
.map(it -> {
|
||||||
try {
|
try {
|
||||||
String type = problemJson.get("type").asString();
|
return baseUrl.toURI().resolve(it);
|
||||||
return type != null ? baseUrl.toURI().resolve(type) : null;
|
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
throw new IllegalArgumentException("Bad base URL", ex);
|
throw new IllegalArgumentException("Bad base URL", ex);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -68,7 +73,7 @@ public class Problem implements Serializable {
|
||||||
* @see #toString()
|
* @see #toString()
|
||||||
*/
|
*/
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
return problemJson.get("title").asString();
|
return problemJson.get("title").map(Value::asString).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +83,7 @@ public class Problem implements Serializable {
|
||||||
* @see #toString()
|
* @see #toString()
|
||||||
*/
|
*/
|
||||||
public String getDetail() {
|
public String getDetail() {
|
||||||
return problemJson.get("detail").asString();
|
return problemJson.get("detail").map(Value::asString).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,29 +91,35 @@ public class Problem implements Serializable {
|
||||||
* an absolute URI.
|
* an absolute URI.
|
||||||
*/
|
*/
|
||||||
public URI getInstance() {
|
public URI getInstance() {
|
||||||
|
return problemJson.get("instance")
|
||||||
|
.map(Value::asString)
|
||||||
|
.map(it -> {
|
||||||
try {
|
try {
|
||||||
String instance = problemJson.get("instance").asString();
|
return baseUrl.toURI().resolve(it);
|
||||||
return instance != null ? baseUrl.toURI().resolve(instance) : null;
|
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
throw new IllegalArgumentException("Bad base URL", ex);
|
throw new IllegalArgumentException("Bad base URL", ex);
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the domain this problem relates to. May be {@code null}.
|
* Returns the domain this problem relates to. May be {@code null}.
|
||||||
*/
|
*/
|
||||||
public String getDomain() {
|
public String getDomain() {
|
||||||
JSON identifier = problemJson.get("identifier").asObject();
|
Value identifier = problemJson.get("identifier");
|
||||||
if (identifier == null) {
|
if (!identifier.isPresent()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
String type = identifier.get("type").asString();
|
JSON json = identifier.asObject();
|
||||||
|
|
||||||
|
String type = json.get("type").asString();
|
||||||
if (!"dns".equals(type)) {
|
if (!"dns".equals(type)) {
|
||||||
throw new AcmeProtocolException("Cannot process a " + type + " identifier");
|
throw new AcmeProtocolException("Cannot process a " + type + " identifier");
|
||||||
}
|
}
|
||||||
|
|
||||||
return identifier.get("value").asString();
|
return json.get("value").asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -117,7 +128,8 @@ public class Problem implements Serializable {
|
||||||
public List<Problem> getSubProblems() {
|
public List<Problem> getSubProblems() {
|
||||||
return unmodifiableList(
|
return unmodifiableList(
|
||||||
problemJson.get("subproblems")
|
problemJson.get("subproblems")
|
||||||
.asArray().stream()
|
.asArray()
|
||||||
|
.stream()
|
||||||
.map(o -> o.asProblem(baseUrl))
|
.map(o -> o.asProblem(baseUrl))
|
||||||
.collect(toList())
|
.collect(toList())
|
||||||
);
|
);
|
||||||
|
|
|
@ -31,6 +31,7 @@ import org.shredzone.acme4j.connector.Resource;
|
||||||
import org.shredzone.acme4j.exception.AcmeException;
|
import org.shredzone.acme4j.exception.AcmeException;
|
||||||
import org.shredzone.acme4j.provider.AcmeProvider;
|
import org.shredzone.acme4j.provider.AcmeProvider;
|
||||||
import org.shredzone.acme4j.toolbox.JSON;
|
import org.shredzone.acme4j.toolbox.JSON;
|
||||||
|
import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A session stores the ACME server URI. It also tracks communication parameters.
|
* A session stores the ACME server URI. It also tracks communication parameters.
|
||||||
|
@ -193,19 +194,18 @@ public class Session {
|
||||||
|
|
||||||
JSON directoryJson = provider().directory(this, getServerUri());
|
JSON directoryJson = provider().directory(this, getServerUri());
|
||||||
|
|
||||||
JSON meta = directoryJson.get("meta").asObject();
|
Value meta = directoryJson.get("meta");
|
||||||
if (meta != null) {
|
if (meta.isPresent()) {
|
||||||
metadata.set(new Metadata(meta));
|
metadata.set(new Metadata(meta.asObject()));
|
||||||
} else {
|
} else {
|
||||||
metadata.set(new Metadata(JSON.empty()));
|
metadata.set(new Metadata(JSON.empty()));
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<Resource, URL> map = new EnumMap<>(Resource.class);
|
Map<Resource, URL> map = new EnumMap<>(Resource.class);
|
||||||
for (Resource res : Resource.values()) {
|
for (Resource res : Resource.values()) {
|
||||||
URL url = directoryJson.get(res.path()).asURL();
|
directoryJson.get(res.path())
|
||||||
if (url != null) {
|
.map(Value::asURL)
|
||||||
map.put(res, url);
|
.ifPresent(url -> map.put(res, url));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resourceMap.set(map);
|
resourceMap.set(map);
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.shredzone.acme4j.connector.Connection;
|
||||||
import org.shredzone.acme4j.exception.AcmeException;
|
import org.shredzone.acme4j.exception.AcmeException;
|
||||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
import org.shredzone.acme4j.toolbox.JSON;
|
import org.shredzone.acme4j.toolbox.JSON;
|
||||||
|
import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||||
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
import org.shredzone.acme4j.toolbox.JSONBuilder;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -55,7 +56,7 @@ public class Challenge extends AcmeJsonResource {
|
||||||
* {@link JSON} challenge data
|
* {@link JSON} challenge data
|
||||||
*/
|
*/
|
||||||
public Challenge(Login login, JSON data) {
|
public Challenge(Login login, JSON data) {
|
||||||
super(login, data.get(KEY_URL).required().asURL());
|
super(login, data.get(KEY_URL).asURL());
|
||||||
setJSON(data);
|
setJSON(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,14 +74,14 @@ public class Challenge extends AcmeJsonResource {
|
||||||
* {@link Status#VALID}, {@link Status#INVALID}.
|
* {@link Status#VALID}, {@link Status#INVALID}.
|
||||||
*/
|
*/
|
||||||
public Status getStatus() {
|
public Status getStatus() {
|
||||||
return getJSON().get(KEY_STATUS).asStatusOrElse(Status.UNKNOWN);
|
return getJSON().get(KEY_STATUS).asStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the validation date, if returned by the server.
|
* Returns the validation date, if returned by the server.
|
||||||
*/
|
*/
|
||||||
public Instant getValidated() {
|
public Instant getValidated() {
|
||||||
return getJSON().get(KEY_VALIDATED).asInstant();
|
return getJSON().get(KEY_VALIDATED).map(Value::asInstant).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,7 +90,9 @@ public class Challenge extends AcmeJsonResource {
|
||||||
* {@link Problem#getSubProblems()}.
|
* {@link Problem#getSubProblems()}.
|
||||||
*/
|
*/
|
||||||
public Problem getError() {
|
public Problem getError() {
|
||||||
return getJSON().get(KEY_ERROR).asProblem(getLocation());
|
return getJSON().get(KEY_ERROR)
|
||||||
|
.map(it -> it.asProblem(getLocation()))
|
||||||
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,13 +118,13 @@ public class Challenge extends AcmeJsonResource {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setJSON(JSON json) {
|
protected void setJSON(JSON json) {
|
||||||
String type = json.get(KEY_TYPE).required().asString();
|
String type = json.get(KEY_TYPE).asString();
|
||||||
|
|
||||||
if (!acceptable(type)) {
|
if (!acceptable(type)) {
|
||||||
throw new AcmeProtocolException("incompatible type " + type + " for this challenge");
|
throw new AcmeProtocolException("incompatible type " + type + " for this challenge");
|
||||||
}
|
}
|
||||||
|
|
||||||
String loc = json.get(KEY_URL).required().asString();
|
String loc = json.get(KEY_URL).asString();
|
||||||
if (loc != null && !loc.equals(getLocation().toString())) {
|
if (loc != null && !loc.equals(getLocation().toString())) {
|
||||||
throw new AcmeProtocolException("challenge has changed its location");
|
throw new AcmeProtocolException("challenge has changed its location");
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class TokenChallenge extends Challenge {
|
||||||
* Gets the token.
|
* Gets the token.
|
||||||
*/
|
*/
|
||||||
protected String getToken() {
|
protected String getToken() {
|
||||||
return getJSON().get(KEY_TOKEN).required().asString();
|
return getJSON().get(KEY_TOKEN).asString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -86,7 +86,7 @@ public abstract class AbstractAcmeProvider implements AcmeProvider {
|
||||||
Objects.requireNonNull(login, "login");
|
Objects.requireNonNull(login, "login");
|
||||||
Objects.requireNonNull(data, "data");
|
Objects.requireNonNull(data, "data");
|
||||||
|
|
||||||
String type = data.get("type").required().asString();
|
String type = data.get("type").asString();
|
||||||
|
|
||||||
BiFunction<Login, JSON, Challenge> constructor = CHALLENGES.get(type);
|
BiFunction<Login, JSON, Challenge> constructor = CHALLENGES.get(type);
|
||||||
if (constructor != null) {
|
if (constructor != null) {
|
||||||
|
|
|
@ -37,6 +37,7 @@ import java.util.NoSuchElementException;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
|
@ -247,6 +248,9 @@ public final class JSON implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A single JSON value. This instance also covers {@code null} values.
|
* A single JSON value. This instance also covers {@code null} values.
|
||||||
|
* <p>
|
||||||
|
* All return values are never {@code null} unless specified otherwise. For optional
|
||||||
|
* parameters, use {@link Value#optional()}.
|
||||||
*/
|
*/
|
||||||
public static final class Value {
|
public static final class Value {
|
||||||
private final String path;
|
private final String path;
|
||||||
|
@ -265,58 +269,53 @@ public final class JSON implements Serializable {
|
||||||
this.val = val;
|
this.val = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this value is {@code null}.
|
||||||
|
*
|
||||||
|
* @return {@code true} if this value is present, {@code false} if {@code null}.
|
||||||
|
*/
|
||||||
|
public boolean isPresent() {
|
||||||
|
return val != null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns this value as {@link Optional}, for further mapping and filtering.
|
* Returns this value as {@link Optional}, for further mapping and filtering.
|
||||||
*
|
*
|
||||||
* @return {@link Optional} of this value, or {@link Optional#empty()} if this
|
* @return {@link Optional} of this value, or {@link Optional#empty()} if this
|
||||||
* value is {@code null}.
|
* value is {@code null}.
|
||||||
|
* @see #map(Function)
|
||||||
*/
|
*/
|
||||||
public Optional<Value> optional() {
|
public Optional<Value> optional() {
|
||||||
return val != null ? Optional.of(this) : Optional.empty();
|
return val != null ? Optional.of(this) : Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the value is present. An {@link AcmeProtocolException} is thrown if
|
* Returns this value as an {@link Optional} of the desired type, for further
|
||||||
* the value is {@code null}.
|
* mapping and filtering.
|
||||||
*
|
*
|
||||||
* @return itself
|
* @param mapper
|
||||||
|
* A {@link Function} that converts a {@link Value} to the desired type
|
||||||
|
* @return {@link Optional} of this value, or {@link Optional#empty()} if this
|
||||||
|
* value is {@code null}.
|
||||||
|
* @see #optional()
|
||||||
*/
|
*/
|
||||||
public Value required() {
|
public <T> Optional<T> map(Function <Value, T> mapper) {
|
||||||
if (val == null) {
|
return optional().map(mapper);
|
||||||
throw new AcmeProtocolException(path + ": required, but not set");
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if the value is present. If not, the default value is used instead.
|
|
||||||
*
|
|
||||||
* @param def Default value
|
|
||||||
* @return itself
|
|
||||||
*/
|
|
||||||
public Value orElse(Object def) {
|
|
||||||
return val != null ? this : new Value(path, def);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as {@link String}.
|
* Returns the value as {@link String}.
|
||||||
*
|
|
||||||
* @return {@link String}, or {@code null} if the value was not set.
|
|
||||||
*/
|
*/
|
||||||
public String asString() {
|
public String asString() {
|
||||||
return val != null ? val.toString() : null;
|
required();
|
||||||
|
return val.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as JSON object.
|
* Returns the value as JSON object.
|
||||||
*
|
|
||||||
* @return {@link JSON}, or {@code null} if the value was not set.
|
|
||||||
*/
|
*/
|
||||||
public JSON asObject() {
|
public JSON asObject() {
|
||||||
if (val == null) {
|
required();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new JSON(path, (Map<String, Object>) val);
|
return new JSON(path, (Map<String, Object>) val);
|
||||||
} catch (ClassCastException ex) {
|
} catch (ClassCastException ex) {
|
||||||
|
@ -329,20 +328,17 @@ public final class JSON implements Serializable {
|
||||||
*
|
*
|
||||||
* @param baseUrl
|
* @param baseUrl
|
||||||
* Base {@link URL} to resolve relative links against
|
* Base {@link URL} to resolve relative links against
|
||||||
* @return {@link Problem}, or {@code null} if the value was not set.
|
|
||||||
*/
|
*/
|
||||||
public Problem asProblem(URL baseUrl) {
|
public Problem asProblem(URL baseUrl) {
|
||||||
if (val == null) {
|
required();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Problem(asObject(), baseUrl);
|
return new Problem(asObject(), baseUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as JSON array.
|
* Returns the value as {@link JSON.Array}.
|
||||||
*
|
* <p>
|
||||||
* @return {@link JSON.Array}, which is empty if the value was not set.
|
* Unlike the other getters, this method returns an empty array if the value is
|
||||||
|
* not set. Use {@link #isPresent()} to find out if the value was actually set.
|
||||||
*/
|
*/
|
||||||
public Array asArray() {
|
public Array asArray() {
|
||||||
if (val == null) {
|
if (val == null) {
|
||||||
|
@ -358,12 +354,9 @@ public final class JSON implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as int.
|
* Returns the value as int.
|
||||||
*
|
|
||||||
* @return integer value
|
|
||||||
*/
|
*/
|
||||||
public int asInt() {
|
public int asInt() {
|
||||||
required();
|
required();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return ((Number) val).intValue();
|
return ((Number) val).intValue();
|
||||||
} catch (ClassCastException ex) {
|
} catch (ClassCastException ex) {
|
||||||
|
@ -373,12 +366,9 @@ public final class JSON implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as boolean.
|
* Returns the value as boolean.
|
||||||
*
|
|
||||||
* @return integer value
|
|
||||||
*/
|
*/
|
||||||
public boolean asBoolean() {
|
public boolean asBoolean() {
|
||||||
required();
|
required();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (Boolean) val;
|
return (Boolean) val;
|
||||||
} catch (ClassCastException ex) {
|
} catch (ClassCastException ex) {
|
||||||
|
@ -388,14 +378,9 @@ public final class JSON implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as {@link URI}.
|
* Returns the value as {@link URI}.
|
||||||
*
|
|
||||||
* @return {@link URI}, or {@code null} if the value was not set.
|
|
||||||
*/
|
*/
|
||||||
public URI asURI() {
|
public URI asURI() {
|
||||||
if (val == null) {
|
required();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new URI(val.toString());
|
return new URI(val.toString());
|
||||||
} catch (URISyntaxException ex) {
|
} catch (URISyntaxException ex) {
|
||||||
|
@ -405,14 +390,9 @@ public final class JSON implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as {@link URL}.
|
* Returns the value as {@link URL}.
|
||||||
*
|
|
||||||
* @return {@link URL}, or {@code null} if the value was not set.
|
|
||||||
*/
|
*/
|
||||||
public URL asURL() {
|
public URL asURL() {
|
||||||
if (val == null) {
|
required();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return new URL(val.toString());
|
return new URL(val.toString());
|
||||||
} catch (MalformedURLException ex) {
|
} catch (MalformedURLException ex) {
|
||||||
|
@ -422,14 +402,9 @@ public final class JSON implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as {@link Instant}.
|
* Returns the value as {@link Instant}.
|
||||||
*
|
|
||||||
* @return {@link Instant}, or {@code null} if the value was not set.
|
|
||||||
*/
|
*/
|
||||||
public Instant asInstant() {
|
public Instant asInstant() {
|
||||||
if (val == null) {
|
required();
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return parseTimestamp(val.toString());
|
return parseTimestamp(val.toString());
|
||||||
} catch (IllegalArgumentException ex) {
|
} catch (IllegalArgumentException ex) {
|
||||||
|
@ -439,30 +414,28 @@ public final class JSON implements Serializable {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the value as base64 decoded byte array.
|
* Returns the value as base64 decoded byte array.
|
||||||
*
|
|
||||||
* @return byte array, or {@code null} if the value was not set.
|
|
||||||
*/
|
*/
|
||||||
public byte[] asBinary() {
|
public byte[] asBinary() {
|
||||||
if (val == null) {
|
required();
|
||||||
return null; //NOSONAR: we want to return null here
|
|
||||||
}
|
|
||||||
|
|
||||||
return AcmeUtils.base64UrlDecode(val.toString());
|
return AcmeUtils.base64UrlDecode(val.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the parsed status.
|
* Returns the parsed {@link Status}.
|
||||||
*
|
|
||||||
* @param def
|
|
||||||
* Default status if value is not present or {@code null}
|
|
||||||
* @return {@link Status}
|
|
||||||
*/
|
*/
|
||||||
public Status asStatusOrElse(Status def) {
|
public Status asStatus() {
|
||||||
if (val == null) {
|
required();
|
||||||
return def;
|
return Status.parse(val.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Status.parse(val.toString());
|
/**
|
||||||
|
* Checks if the value is present. An {@link AcmeProtocolException} is thrown if
|
||||||
|
* the value is {@code null}.
|
||||||
|
*/
|
||||||
|
private void required() {
|
||||||
|
if (!isPresent()) {
|
||||||
|
throw new AcmeProtocolException(path + ": required, but not set");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -121,7 +121,6 @@ public class AccountBuilderTest {
|
||||||
|
|
||||||
JSON binding = claims.toJSON()
|
JSON binding = claims.toJSON()
|
||||||
.get("externalAccountBinding")
|
.get("externalAccountBinding")
|
||||||
.required()
|
|
||||||
.asObject();
|
.asObject();
|
||||||
|
|
||||||
String encodedHeader = binding.get("protected").asString();
|
String encodedHeader = binding.get("protected").asString();
|
||||||
|
|
|
@ -60,8 +60,6 @@ public class ChallengeTest {
|
||||||
assertThat(challenge.getValidated(), is(parseTimestamp("2015-12-12T17:19:36.336785823Z")));
|
assertThat(challenge.getValidated(), is(parseTimestamp("2015-12-12T17:19:36.336785823Z")));
|
||||||
assertThat(challenge.getJSON().get("type").asString(), is("generic-01"));
|
assertThat(challenge.getJSON().get("type").asString(), is("generic-01"));
|
||||||
assertThat(challenge.getJSON().get("url").asURL(), is(url("http://example.com/challenge/123")));
|
assertThat(challenge.getJSON().get("url").asURL(), is(url("http://example.com/challenge/123")));
|
||||||
assertThat(challenge.getJSON().get("notPresent").asString(), is(nullValue()));
|
|
||||||
assertThat(challenge.getJSON().get("notPresentUrl").asURL(), is(nullValue()));
|
|
||||||
|
|
||||||
Problem error = challenge.getError();
|
Problem error = challenge.getError();
|
||||||
assertThat(error, is(notNullValue()));
|
assertThat(error, is(notNullValue()));
|
||||||
|
|
|
@ -40,6 +40,7 @@ import org.junit.Test;
|
||||||
import org.shredzone.acme4j.Problem;
|
import org.shredzone.acme4j.Problem;
|
||||||
import org.shredzone.acme4j.Status;
|
import org.shredzone.acme4j.Status;
|
||||||
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
import org.shredzone.acme4j.exception.AcmeProtocolException;
|
||||||
|
import org.shredzone.acme4j.toolbox.JSON.Value;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit test for {@link JSON}.
|
* Unit test for {@link JSON}.
|
||||||
|
@ -198,10 +199,12 @@ public class JSONTest {
|
||||||
assertThat(json.get("uri").asURI(), is(URI.create("mailto:foo@example.com")));
|
assertThat(json.get("uri").asURI(), is(URI.create("mailto:foo@example.com")));
|
||||||
assertThat(json.get("url").asURL(), is(url("http://example.com")));
|
assertThat(json.get("url").asURL(), is(url("http://example.com")));
|
||||||
assertThat(json.get("date").asInstant(), is(date));
|
assertThat(json.get("date").asInstant(), is(date));
|
||||||
assertThat(json.get("status").asStatusOrElse(Status.INVALID), is(Status.VALID));
|
assertThat(json.get("status").asStatus(), is(Status.VALID));
|
||||||
assertThat(json.get("binary").asBinary(), is("Chainsaw".getBytes()));
|
assertThat(json.get("binary").asBinary(), is("Chainsaw".getBytes()));
|
||||||
|
|
||||||
|
assertThat(json.get("text").isPresent(), is(true));
|
||||||
assertThat(json.get("text").optional().isPresent(), is(true));
|
assertThat(json.get("text").optional().isPresent(), is(true));
|
||||||
|
assertThat(json.get("text").map(Value::asString).isPresent(), is(true));
|
||||||
|
|
||||||
JSON.Array array = json.get("array").asArray();
|
JSON.Array array = json.get("array").asArray();
|
||||||
assertThat(array.get(0).asString(), is("foo"));
|
assertThat(array.get(0).asString(), is("foo"));
|
||||||
|
@ -230,20 +233,65 @@ public class JSONTest {
|
||||||
JSON json = TestUtils.getJSON("datatypes");
|
JSON json = TestUtils.getJSON("datatypes");
|
||||||
|
|
||||||
assertThat(json.get("none"), is(notNullValue()));
|
assertThat(json.get("none"), is(notNullValue()));
|
||||||
assertThat(json.get("none").asString(), is(nullValue()));
|
assertThat(json.get("none").isPresent(), is(false));
|
||||||
assertThat(json.get("none").asURI(), is(nullValue()));
|
|
||||||
assertThat(json.get("none").asURL(), is(nullValue()));
|
|
||||||
assertThat(json.get("none").asInstant(), is(nullValue()));
|
|
||||||
assertThat(json.get("none").asObject(), is(nullValue()));
|
|
||||||
assertThat(json.get("none").asStatusOrElse(Status.INVALID), is(Status.INVALID));
|
|
||||||
assertThat(json.get("none").asBinary(), is(nullValue()));
|
|
||||||
assertThat(json.get("none").asProblem(BASE_URL), is(nullValue()));
|
|
||||||
|
|
||||||
assertThat(json.get("none").orElse("foo").asString(), is("foo"));
|
|
||||||
assertThat(json.get("none").orElse(42).asInt(), is(42));
|
|
||||||
assertThat(json.get("none").orElse(true).asBoolean(), is(true));
|
|
||||||
|
|
||||||
assertThat(json.get("none").optional().isPresent(), is(false));
|
assertThat(json.get("none").optional().isPresent(), is(false));
|
||||||
|
assertThat(json.get("none").map(Value::asString).isPresent(), is(false));
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asString();
|
||||||
|
fail("asString did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asURI();
|
||||||
|
fail("asURI did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asURL();
|
||||||
|
fail("asURL did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asInstant();
|
||||||
|
fail("asInstant did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asObject();
|
||||||
|
fail("asObject did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asStatus();
|
||||||
|
fail("asStatus did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asBinary();
|
||||||
|
fail("asBinary did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json.get("none").asProblem(BASE_URL);
|
||||||
|
fail("asProblem did not fail");
|
||||||
|
} catch (AcmeProtocolException ex) {
|
||||||
|
// expected
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
json.get("none").asInt();
|
json.get("none").asInt();
|
||||||
|
@ -258,16 +306,6 @@ public class JSONTest {
|
||||||
} catch (AcmeProtocolException ex) {
|
} catch (AcmeProtocolException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
json.get("none").required();
|
|
||||||
fail("required did not fail");
|
|
||||||
} catch (AcmeProtocolException ex) {
|
|
||||||
// expected
|
|
||||||
}
|
|
||||||
|
|
||||||
JSON.Value textv = json.get("text");
|
|
||||||
assertThat(textv.required(), is(textv));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue