Adding a uniform configuration for all json/yaml mapper use cases: part 1

This commit is contained in:
Sergey Skrobotov 2023-02-23 16:11:05 -08:00
parent 6ee9c6ad46
commit b9b4e3fdd8
38 changed files with 250 additions and 121 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2021-2022 Signal Messenger, LLC * Copyright 2021 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -81,7 +81,7 @@ public class HCaptchaClient implements CaptchaClient {
throw new IOException("hCaptcha http failure : " + response.statusCode()); throw new IOException("hCaptcha http failure : " + response.statusCode());
} }
final HCaptchaResponse hCaptchaResponse = SystemMapper.getMapper() final HCaptchaResponse hCaptchaResponse = SystemMapper.jsonMapper()
.readValue(response.body(), HCaptchaResponse.class); .readValue(response.body(), HCaptchaResponse.class);
logger.debug("received hCaptcha response: {}", hCaptchaResponse); logger.debug("received hCaptcha response: {}", hCaptchaResponse);

View File

@ -1,11 +1,13 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.currency; package org.whispersystems.textsecuregcm.currency;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.URI; import java.net.URI;
@ -13,6 +15,9 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.util.Map; import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.util.SystemMapper;
public class CoinMarketCapClient { public class CoinMarketCapClient {
@ -64,7 +69,7 @@ public class CoinMarketCapClient {
@VisibleForTesting @VisibleForTesting
static CoinMarketCapResponse parseResponse(final String responseJson) throws JsonProcessingException { static CoinMarketCapResponse parseResponse(final String responseJson) throws JsonProcessingException {
return SystemMapper.getMapper().readValue(responseJson, CoinMarketCapResponse.class); return SystemMapper.jsonMapper().readValue(responseJson, CoinMarketCapResponse.class);
} }
@VisibleForTesting @VisibleForTesting

View File

@ -1,8 +1,11 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.currency; package org.whispersystems.textsecuregcm.currency;
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonProperty;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import java.io.IOException; import java.io.IOException;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.net.URI; import java.net.URI;
@ -10,6 +13,7 @@ import java.net.http.HttpClient;
import java.net.http.HttpRequest; import java.net.http.HttpRequest;
import java.net.http.HttpResponse; import java.net.http.HttpResponse;
import java.util.Map; import java.util.Map;
import org.whispersystems.textsecuregcm.util.SystemMapper;
public class FixerClient { public class FixerClient {
@ -35,7 +39,7 @@ public class FixerClient {
throw new FixerException("Bad response: " + response.statusCode() + " " + response.toString()); throw new FixerException("Bad response: " + response.statusCode() + " " + response.toString());
} }
FixerResponse parsedResponse = SystemMapper.getMapper().readValue(response.body(), FixerResponse.class); FixerResponse parsedResponse = SystemMapper.jsonMapper().readValue(response.body(), FixerResponse.class);
if (parsedResponse.success) return parsedResponse.rates; if (parsedResponse.success) return parsedResponse.rates;
else throw new FixerException("Got failed response!"); else throw new FixerException("Got failed response!");

View File

@ -12,7 +12,6 @@ import com.codahale.metrics.MetricRegistry;
import com.codahale.metrics.SharedMetricRegistries; import com.codahale.metrics.SharedMetricRegistries;
import com.codahale.metrics.Timer; import com.codahale.metrics.Timer;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -26,8 +25,6 @@ public class StaticRateLimiter implements RateLimiter {
private static final Logger logger = LoggerFactory.getLogger(StaticRateLimiter.class); private static final Logger logger = LoggerFactory.getLogger(StaticRateLimiter.class);
private static final ObjectMapper MAPPER = SystemMapper.getMapper();
protected final String name; protected final String name;
private final RateLimiterConfig config; private final RateLimiterConfig config;
@ -81,7 +78,7 @@ public class StaticRateLimiter implements RateLimiter {
private void setBucket(final String key, final LeakyBucket bucket) { private void setBucket(final String key, final LeakyBucket bucket) {
try { try {
final String serialized = bucket.serialize(MAPPER); final String serialized = bucket.serialize(SystemMapper.jsonMapper());
cacheCluster.useCluster(connection -> connection.sync().setex( cacheCluster.useCluster(connection -> connection.sync().setex(
getBucketName(key), getBucketName(key),
(int) Math.ceil((config.bucketSize() / config.leakRatePerMillis()) / 1000), (int) Math.ceil((config.bucketSize() / config.leakRatePerMillis()) / 1000),
@ -96,7 +93,7 @@ public class StaticRateLimiter implements RateLimiter {
final String serialized = cacheCluster.withCluster(connection -> connection.sync().get(getBucketName(key))); final String serialized = cacheCluster.withCluster(connection -> connection.sync().get(getBucketName(key)));
if (serialized != null) { if (serialized != null) {
return LeakyBucket.fromSerialized(MAPPER, serialized); return LeakyBucket.fromSerialized(SystemMapper.jsonMapper(), serialized);
} }
} catch (final IOException e) { } catch (final IOException e) {
logger.warn("Deserialization error", e); logger.warn("Deserialization error", e);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2022 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -106,7 +106,7 @@ public class PushLatencyManager {
void recordPushSent(final UUID accountUuid, final long deviceId, final boolean isVoip) { void recordPushSent(final UUID accountUuid, final long deviceId, final boolean isVoip) {
try { try {
final String recordJson = SystemMapper.getMapper().writeValueAsString( final String recordJson = SystemMapper.jsonMapper().writeValueAsString(
new PushRecord(Instant.now(clock), isVoip ? PushType.VOIP : PushType.STANDARD)); new PushRecord(Instant.now(clock), isVoip ? PushType.VOIP : PushType.STANDARD));
redisCluster.useCluster(connection -> redisCluster.useCluster(connection ->
@ -159,7 +159,7 @@ public class PushLatencyManager {
.thenApply(recordJson -> { .thenApply(recordJson -> {
if (StringUtils.isNotEmpty(recordJson)) { if (StringUtils.isNotEmpty(recordJson)) {
try { try {
return SystemMapper.getMapper().readValue(recordJson, PushRecord.class); return SystemMapper.jsonMapper().readValue(recordJson, PushRecord.class);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
return null; return null;
} }

View File

@ -14,9 +14,6 @@ import io.micrometer.core.instrument.Metrics;
import io.micrometer.core.instrument.Timer; import io.micrometer.core.instrument.Timer;
import java.io.IOException; import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Clock; import java.time.Clock;
import java.time.Duration; import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
@ -271,7 +268,7 @@ public class Accounts extends AbstractDynamoDbStore {
"#version", ATTR_VERSION)) "#version", ATTR_VERSION))
.expressionAttributeValues(Map.of( .expressionAttributeValues(Map.of(
":number", numberAttr, ":number", numberAttr,
":data", AttributeValues.fromByteArray(SystemMapper.getMapper().writeValueAsBytes(account)), ":data", AttributeValues.fromByteArray(SystemMapper.jsonMapper().writeValueAsBytes(account)),
":cds", AttributeValues.fromBool(account.shouldBeVisibleInDirectory()), ":cds", AttributeValues.fromBool(account.shouldBeVisibleInDirectory()),
":pni", pniAttr, ":pni", pniAttr,
":version", AttributeValues.fromInt(account.getVersion()), ":version", AttributeValues.fromInt(account.getVersion()),
@ -342,7 +339,7 @@ public class Accounts extends AbstractDynamoDbStore {
.conditionExpression("#version = :version") .conditionExpression("#version = :version")
.expressionAttributeNames(Map.of("#data", ATTR_ACCOUNT_DATA, "#version", ATTR_VERSION)) .expressionAttributeNames(Map.of("#data", ATTR_ACCOUNT_DATA, "#version", ATTR_VERSION))
.expressionAttributeValues(Map.of( .expressionAttributeValues(Map.of(
":data", AttributeValues.fromByteArray(SystemMapper.getMapper().writeValueAsBytes(account)), ":data", AttributeValues.fromByteArray(SystemMapper.jsonMapper().writeValueAsBytes(account)),
":version", AttributeValues.fromInt(account.getVersion()), ":version", AttributeValues.fromInt(account.getVersion()),
":version_increment", AttributeValues.fromInt(1))) ":version_increment", AttributeValues.fromInt(1)))
.build()) .build())
@ -423,7 +420,7 @@ public class Accounts extends AbstractDynamoDbStore {
"#username_hash", ATTR_USERNAME_HASH, "#username_hash", ATTR_USERNAME_HASH,
"#version", ATTR_VERSION)) "#version", ATTR_VERSION))
.expressionAttributeValues(Map.of( .expressionAttributeValues(Map.of(
":data", AttributeValues.fromByteArray(SystemMapper.getMapper().writeValueAsBytes(account)), ":data", AttributeValues.fromByteArray(SystemMapper.jsonMapper().writeValueAsBytes(account)),
":username_hash", AttributeValues.fromByteArray(usernameHash), ":username_hash", AttributeValues.fromByteArray(usernameHash),
":version", AttributeValues.fromInt(account.getVersion()), ":version", AttributeValues.fromInt(account.getVersion()),
":version_increment", AttributeValues.fromInt(1))) ":version_increment", AttributeValues.fromInt(1)))
@ -478,7 +475,7 @@ public class Accounts extends AbstractDynamoDbStore {
"#username_hash", ATTR_USERNAME_HASH, "#username_hash", ATTR_USERNAME_HASH,
"#version", ATTR_VERSION)) "#version", ATTR_VERSION))
.expressionAttributeValues(Map.of( .expressionAttributeValues(Map.of(
":data", AttributeValues.fromByteArray(SystemMapper.getMapper().writeValueAsBytes(account)), ":data", AttributeValues.fromByteArray(SystemMapper.jsonMapper().writeValueAsBytes(account)),
":version", AttributeValues.fromInt(account.getVersion()), ":version", AttributeValues.fromInt(account.getVersion()),
":version_increment", AttributeValues.fromInt(1))) ":version_increment", AttributeValues.fromInt(1)))
.build()) .build())
@ -523,7 +520,7 @@ public class Accounts extends AbstractDynamoDbStore {
"#cds", ATTR_CANONICALLY_DISCOVERABLE, "#cds", ATTR_CANONICALLY_DISCOVERABLE,
"#version", ATTR_VERSION)); "#version", ATTR_VERSION));
final Map<String, AttributeValue> attrValues = new HashMap<>(Map.of( final Map<String, AttributeValue> attrValues = new HashMap<>(Map.of(
":data", AttributeValues.fromByteArray(SystemMapper.getMapper().writeValueAsBytes(account)), ":data", AttributeValues.fromByteArray(SystemMapper.jsonMapper().writeValueAsBytes(account)),
":cds", AttributeValues.fromBool(account.shouldBeVisibleInDirectory()), ":cds", AttributeValues.fromBool(account.shouldBeVisibleInDirectory()),
":version", AttributeValues.fromInt(account.getVersion()), ":version", AttributeValues.fromInt(account.getVersion()),
":version_increment", AttributeValues.fromInt(1))); ":version_increment", AttributeValues.fromInt(1)));
@ -720,7 +717,7 @@ public class Accounts extends AbstractDynamoDbStore {
KEY_ACCOUNT_UUID, uuidAttr, KEY_ACCOUNT_UUID, uuidAttr,
ATTR_ACCOUNT_E164, numberAttr, ATTR_ACCOUNT_E164, numberAttr,
ATTR_PNI_UUID, pniUuidAttr, ATTR_PNI_UUID, pniUuidAttr,
ATTR_ACCOUNT_DATA, AttributeValues.fromByteArray(SystemMapper.getMapper().writeValueAsBytes(account)), ATTR_ACCOUNT_DATA, AttributeValues.fromByteArray(SystemMapper.jsonMapper().writeValueAsBytes(account)),
ATTR_VERSION, AttributeValues.fromInt(account.getVersion()), ATTR_VERSION, AttributeValues.fromInt(account.getVersion()),
ATTR_CANONICALLY_DISCOVERABLE, AttributeValues.fromBool(account.shouldBeVisibleInDirectory()))); ATTR_CANONICALLY_DISCOVERABLE, AttributeValues.fromBool(account.shouldBeVisibleInDirectory())));
@ -842,7 +839,7 @@ public class Accounts extends AbstractDynamoDbStore {
throw new RuntimeException("item missing values"); throw new RuntimeException("item missing values");
} }
try { try {
final Account account = SystemMapper.getMapper().readValue(item.get(ATTR_ACCOUNT_DATA).b().asByteArray(), Account.class); final Account account = SystemMapper.jsonMapper().readValue(item.get(ATTR_ACCOUNT_DATA).b().asByteArray(), Account.class);
final UUID accountIdentifier = UUIDUtil.fromByteBuffer(item.get(KEY_ACCOUNT_UUID).b().asByteBuffer()); final UUID accountIdentifier = UUIDUtil.fromByteBuffer(item.get(KEY_ACCOUNT_UUID).b().asByteBuffer());
final UUID phoneNumberIdentifierFromAttribute = AttributeValues.getUUID(item, ATTR_PNI_UUID, null); final UUID phoneNumberIdentifierFromAttribute = AttributeValues.getUUID(item, ATTR_PNI_UUID, null);

View File

@ -96,7 +96,7 @@ public class AccountsManager {
private final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager; private final RegistrationRecoveryPasswordsManager registrationRecoveryPasswordsManager;
private final Clock clock; private final Clock clock;
private static final ObjectMapper mapper = SystemMapper.getMapper(); private static final ObjectMapper mapper = SystemMapper.jsonMapper();
// An account that's used at least daily will get reset in the cache at least once per day when its "last seen" // An account that's used at least daily will get reset in the cache at least once per day when its "last seen"
// timestamp updates; expiring entries after two days will help clear out "zombie" cache entries that are read // timestamp updates; expiring entries after two days will help clear out "zombie" cache entries that are read

View File

@ -1,12 +1,13 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.storage; package org.whispersystems.textsecuregcm.storage;
import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name; import static org.whispersystems.textsecuregcm.metrics.MetricsUtil.name;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import io.micrometer.core.instrument.Metrics; import io.micrometer.core.instrument.Metrics;
import java.time.Duration; import java.time.Duration;
@ -18,6 +19,7 @@ import javax.validation.Validation;
import javax.validation.Validator; import javax.validation.Validator;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import org.whispersystems.textsecuregcm.util.Util; import org.whispersystems.textsecuregcm.util.Util;
import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
import software.amazon.awssdk.services.appconfigdata.AppConfigDataClient; import software.amazon.awssdk.services.appconfigdata.AppConfigDataClient;
@ -39,11 +41,6 @@ public class DynamicConfigurationManager<T> {
private String configurationToken = null; private String configurationToken = null;
private boolean initialized = false; private boolean initialized = false;
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(new YAMLFactory())
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.registerModule(new JavaTimeModule());
private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator(); private static final Validator VALIDATOR = Validation.buildDefaultValidatorFactory().getValidator();
private static final String ERROR_COUNTER_NAME = name(DynamicConfigurationManager.class, "error"); private static final String ERROR_COUNTER_NAME = name(DynamicConfigurationManager.class, "error");
@ -143,7 +140,7 @@ public class DynamicConfigurationManager<T> {
@VisibleForTesting @VisibleForTesting
public static <T> Optional<T> parseConfiguration(final String configurationYaml, final Class<T> configurationClass) public static <T> Optional<T> parseConfiguration(final String configurationYaml, final Class<T> configurationClass)
throws JsonProcessingException { throws JsonProcessingException {
final T configuration = OBJECT_MAPPER.readValue(configurationYaml, configurationClass); final T configuration = SystemMapper.yamlMapper().readValue(configurationYaml, configurationClass);
final Set<ConstraintViolation<T>> violations = VALIDATOR.validate(configuration); final Set<ConstraintViolation<T>> violations = VALIDATOR.validate(configuration);
final Optional<T> maybeDynamicConfiguration; final Optional<T> maybeDynamicConfiguration;

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -30,7 +30,7 @@ public class ProfilesManager {
final FaultTolerantRedisCluster cacheCluster) { final FaultTolerantRedisCluster cacheCluster) {
this.profiles = profiles; this.profiles = profiles;
this.cacheCluster = cacheCluster; this.cacheCluster = cacheCluster;
this.mapper = SystemMapper.getMapper(); this.mapper = SystemMapper.jsonMapper();
} }
public void set(UUID uuid, VersionedProfile versionedProfile) { public void set(UUID uuid, VersionedProfile versionedProfile) {

View File

@ -84,7 +84,7 @@ public abstract class SerializedExpireableJsonDynamoStore<T> {
final Map<String, AttributeValue> attributeValueMap = new HashMap<>(Map.of( final Map<String, AttributeValue> attributeValueMap = new HashMap<>(Map.of(
KEY_KEY, AttributeValues.fromString(key), KEY_KEY, AttributeValues.fromString(key),
ATTR_SERIALIZED_VALUE, ATTR_SERIALIZED_VALUE,
AttributeValues.fromString(SystemMapper.getMapper().writeValueAsString(v)))); AttributeValues.fromString(SystemMapper.jsonMapper().writeValueAsString(v))));
if (v instanceof Expireable ev) { if (v instanceof Expireable ev) {
attributeValueMap.put(ATTR_TTL, AttributeValues.fromLong(getExpirationTimestamp(ev))); attributeValueMap.put(ATTR_TTL, AttributeValues.fromLong(getExpirationTimestamp(ev)));
} }
@ -117,7 +117,7 @@ public abstract class SerializedExpireableJsonDynamoStore<T> {
try { try {
return response.hasItem() return response.hasItem()
? filterMaybeExpiredValue( ? filterMaybeExpiredValue(
SystemMapper.getMapper() SystemMapper.jsonMapper()
.readValue(response.item().get(ATTR_SERIALIZED_VALUE).s(), deserializationTargetClass)) .readValue(response.item().get(ATTR_SERIALIZED_VALUE).s(), deserializationTargetClass))
: Optional.empty(); : Optional.empty();
} catch (final JsonProcessingException e) { } catch (final JsonProcessingException e) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2021 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -58,7 +58,7 @@ public class VerificationCodeStore {
.tableName(tableName) .tableName(tableName)
.item(Map.of( .item(Map.of(
KEY_E164, AttributeValues.fromString(number), KEY_E164, AttributeValues.fromString(number),
ATTR_STORED_CODE, AttributeValues.fromString(SystemMapper.getMapper().writeValueAsString(verificationCode)), ATTR_STORED_CODE, AttributeValues.fromString(SystemMapper.jsonMapper().writeValueAsString(verificationCode)),
ATTR_TTL, AttributeValues.fromLong(getExpirationTimestamp(verificationCode)))) ATTR_TTL, AttributeValues.fromLong(getExpirationTimestamp(verificationCode))))
.build()); .build());
} catch (final JsonProcessingException e) { } catch (final JsonProcessingException e) {
@ -84,7 +84,7 @@ public class VerificationCodeStore {
try { try {
return response.hasItem() return response.hasItem()
? filterMaybeExpiredCode( ? filterMaybeExpiredCode(
SystemMapper.getMapper().readValue(response.item().get(ATTR_STORED_CODE).s(), StoredVerificationCode.class)) SystemMapper.jsonMapper().readValue(response.item().get(ATTR_STORED_CODE).s(), StoredVerificationCode.class))
: Optional.empty(); : Optional.empty();
} catch (final JsonProcessingException e) { } catch (final JsonProcessingException e) {
log.error("Failed to parse stored verification code", e); log.error("Failed to parse stored verification code", e);

View File

@ -19,7 +19,6 @@ import com.braintreegateway.TransactionSearchRequest;
import com.braintreegateway.exceptions.BraintreeException; import com.braintreegateway.exceptions.BraintreeException;
import com.braintreegateway.exceptions.NotFoundException; import com.braintreegateway.exceptions.NotFoundException;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.time.Instant; import java.time.Instant;
import java.util.Comparator; import java.util.Comparator;
@ -40,6 +39,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration; import org.whispersystems.textsecuregcm.configuration.CircuitBreakerConfiguration;
import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient; import org.whispersystems.textsecuregcm.http.FaultTolerantHttpClient;
import org.whispersystems.textsecuregcm.util.SystemMapper;
public class BraintreeManager implements SubscriptionProcessorManager { public class BraintreeManager implements SubscriptionProcessorManager {
@ -374,7 +374,7 @@ public class BraintreeManager implements SubscriptionProcessorManager {
private long getLevelForPlan(final Plan plan) { private long getLevelForPlan(final Plan plan) {
final BraintreePlanMetadata metadata; final BraintreePlanMetadata metadata;
try { try {
metadata = new ObjectMapper().readValue(plan.getDescription(), BraintreePlanMetadata.class); metadata = SystemMapper.jsonMapper().readValue(plan.getDescription(), BraintreePlanMetadata.class);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
@ -477,7 +477,7 @@ public class BraintreeManager implements SubscriptionProcessorManager {
final BraintreePlanMetadata metadata; final BraintreePlanMetadata metadata;
try { try {
metadata = new ObjectMapper().readValue(plan.getDescription(), BraintreePlanMetadata.class); metadata = SystemMapper.jsonMapper().readValue(plan.getDescription(), BraintreePlanMetadata.class);
} catch (JsonProcessingException e) { } catch (JsonProcessingException e) {
throw new RuntimeException(e); throw new RuntimeException(e);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -7,28 +7,55 @@ package org.whispersystems.textsecuregcm.util;
import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.vdurmont.semver4j.Semver;
import java.io.IOException;
import javax.annotation.Nonnull; import javax.annotation.Nonnull;
public class SystemMapper { public class SystemMapper {
private static final ObjectMapper MAPPER = build(); private static final ObjectMapper JSON_MAPPER = configureMapper(new ObjectMapper());
private static final ObjectMapper YAML_MAPPER = configureMapper(new YAMLMapper());
@Nonnull @Nonnull
public static ObjectMapper getMapper() { public static ObjectMapper jsonMapper() {
return MAPPER; return JSON_MAPPER;
} }
@Nonnull @Nonnull
private static ObjectMapper build() { public static ObjectMapper yamlMapper() {
final ObjectMapper mapper = new ObjectMapper(); return YAML_MAPPER;
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE); }
mapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
mapper.registerModule(new JavaTimeModule()); public static ObjectMapper configureMapper(final ObjectMapper mapper) {
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
return mapper; .setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.NONE)
.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY)
.registerModules(
applicationModule(),
new JavaTimeModule(),
new Jdk8Module());
}
private static Module applicationModule() {
return new SimpleModule()
.addDeserializer(Semver.class, new JsonDeserializer<>() {
@Override
public Semver deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException {
final String strValue = p.readValueAs(String.class);
return strValue != null ? new Semver(strValue) : null;
}
});
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -17,7 +17,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.protobuf.InvalidProtocolBufferException; import com.google.protobuf.InvalidProtocolBufferException;
@ -76,6 +75,7 @@ import org.whispersystems.textsecuregcm.storage.Account;
import org.whispersystems.textsecuregcm.storage.AccountsManager; import org.whispersystems.textsecuregcm.storage.AccountsManager;
import org.whispersystems.textsecuregcm.storage.Device; import org.whispersystems.textsecuregcm.storage.Device;
import org.whispersystems.textsecuregcm.tests.util.DevicesHelper; import org.whispersystems.textsecuregcm.tests.util.DevicesHelper;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import org.whispersystems.websocket.WebSocketResourceProvider; import org.whispersystems.websocket.WebSocketResourceProvider;
import org.whispersystems.websocket.auth.WebsocketAuthValueFactoryProvider; import org.whispersystems.websocket.auth.WebsocketAuthValueFactoryProvider;
import org.whispersystems.websocket.logging.WebsocketRequestLog; import org.whispersystems.websocket.logging.WebsocketRequestLog;
@ -326,7 +326,7 @@ class AuthEnablementRefreshRequirementProviderTest {
resourceConfig.register(new TestResource()); resourceConfig.register(new TestResource());
resourceConfig.register(new WebSocketSessionContextValueFactoryProvider.Binder()); resourceConfig.register(new WebSocketSessionContextValueFactoryProvider.Binder());
resourceConfig.register(new WebsocketAuthValueFactoryProvider.Binder<>(TestPrincipal.class)); resourceConfig.register(new WebsocketAuthValueFactoryProvider.Binder<>(TestPrincipal.class));
resourceConfig.register(new JacksonMessageBodyProvider(new ObjectMapper())); resourceConfig.register(new JacksonMessageBodyProvider(SystemMapper.jsonMapper()));
ApplicationHandler applicationHandler = new ApplicationHandler(resourceConfig); ApplicationHandler applicationHandler = new ApplicationHandler(resourceConfig);
WebsocketRequestLog requestLog = mock(WebsocketRequestLog.class); WebsocketRequestLog requestLog = mock(WebsocketRequestLog.class);

View File

@ -213,7 +213,7 @@ class AccountControllerTest {
.addProvider(new ImpossiblePhoneNumberExceptionMapper()) .addProvider(new ImpossiblePhoneNumberExceptionMapper())
.addProvider(new NonNormalizedPhoneNumberExceptionMapper()) .addProvider(new NonNormalizedPhoneNumberExceptionMapper())
.addProvider(new RateLimitByIpFilter(rateLimiters)) .addProvider(new RateLimitByIpFilter(rateLimiters))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new AccountController(pendingAccountsManager, .addResource(new AccountController(pendingAccountsManager,
accountsManager, accountsManager,

View File

@ -105,7 +105,7 @@ class AccountControllerV2Test {
.addProvider(new RateLimitExceededExceptionMapper()) .addProvider(new RateLimitExceededExceptionMapper())
.addProvider(new ImpossiblePhoneNumberExceptionMapper()) .addProvider(new ImpossiblePhoneNumberExceptionMapper())
.addProvider(new NonNormalizedPhoneNumberExceptionMapper()) .addProvider(new NonNormalizedPhoneNumberExceptionMapper())
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource( .addResource(
new AccountControllerV2(accountsManager, changeNumberManager, new AccountControllerV2(accountsManager, changeNumberManager,

View File

@ -47,7 +47,7 @@ class ChallengeControllerTest {
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
Set.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) Set.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new RateLimitExceededExceptionMapper()) .addResource(new RateLimitExceededExceptionMapper())
.addResource(challengeController) .addResource(challengeController)

View File

@ -59,7 +59,6 @@ import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import org.glassfish.jersey.server.ServerProperties; import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory; import org.glassfish.jersey.test.grizzly.GrizzlyWebTestContainerFactory;
import org.hamcrest.CoreMatchers;
import org.hamcrest.Matcher; import org.hamcrest.Matcher;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
@ -221,7 +220,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.DISABLED_UUID, AuthHelper.DISABLED_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -235,7 +234,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -256,7 +255,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_single_device_not_urgent.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_single_device_not_urgent.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -277,7 +276,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_PNI)) .target(String.format("/v1/messages/%s", SINGLE_DEVICE_PNI))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -297,7 +296,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_null_message_in_list.json"), IncomingMessageList.class), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_null_message_in_list.json"), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
assertThat("Bad request", response.getStatus(), is(equalTo(422))); assertThat("Bad request", response.getStatus(), is(equalTo(422)));
@ -310,7 +309,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID))
.request() .request()
.header(OptionalAccess.UNIDENTIFIED, Base64.getEncoder().encodeToString(UNIDENTIFIED_ACCESS_BYTES)) .header(OptionalAccess.UNIDENTIFIED, Base64.getEncoder().encodeToString(UNIDENTIFIED_ACCESS_BYTES))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -329,7 +328,7 @@ class MessageControllerTest {
resources.getJerseyTest() resources.getJerseyTest()
.target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID)) .target(String.format("/v1/messages/%s", SINGLE_DEVICE_UUID))
.request() .request()
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -343,7 +342,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_single_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -363,7 +362,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_extra_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_extra_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -383,7 +382,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_multi_device.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_multi_device.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -403,7 +402,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) .target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_multi_device_not_urgent.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_multi_device_not_urgent.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -423,7 +422,7 @@ class MessageControllerTest {
.target(String.format("/v1/messages/%s", MULTI_DEVICE_PNI)) .target(String.format("/v1/messages/%s", MULTI_DEVICE_PNI))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_multi_device_pni.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_multi_device_pni.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -438,7 +437,7 @@ class MessageControllerTest {
resources.getJerseyTest().target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID)) resources.getJerseyTest().target(String.format("/v1/messages/%s", MULTI_DEVICE_UUID))
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture("fixtures/current_message_registration_id.json"), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture("fixtures/current_message_registration_id.json"),
IncomingMessageList.class), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
@ -837,7 +836,7 @@ class MessageControllerTest {
.request() .request()
.header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD)) .header("Authorization", AuthHelper.getAuthHeader(AuthHelper.VALID_UUID, AuthHelper.VALID_PASSWORD))
.header(HttpHeaders.USER_AGENT, "Test-UA") .header(HttpHeaders.USER_AGENT, "Test-UA")
.put(Entity.entity(SystemMapper.getMapper().readValue(jsonFixture(payloadFilename), IncomingMessageList.class), .put(Entity.entity(SystemMapper.jsonMapper().readValue(jsonFixture(payloadFilename), IncomingMessageList.class),
MediaType.APPLICATION_JSON_TYPE)); MediaType.APPLICATION_JSON_TYPE));
if (expectOk) { if (expectOk) {
@ -1031,7 +1030,7 @@ class MessageControllerTest {
String accessBytes = Base64.getEncoder().encodeToString(UNIDENTIFIED_ACCESS_BYTES); String accessBytes = Base64.getEncoder().encodeToString(UNIDENTIFIED_ACCESS_BYTES);
String json = jsonFixture("fixtures/current_message_single_device.json"); String json = jsonFixture("fixtures/current_message_single_device.json");
UUID unknownUUID = UUID.randomUUID(); UUID unknownUUID = UUID.randomUUID();
IncomingMessageList list = SystemMapper.getMapper().readValue(json, IncomingMessageList.class); IncomingMessageList list = SystemMapper.jsonMapper().readValue(json, IncomingMessageList.class);
Response response = Response response =
resources.getJerseyTest() resources.getJerseyTest()
.target(String.format("/v1/messages/%s", unknownUUID)) .target(String.format("/v1/messages/%s", unknownUUID))

View File

@ -147,7 +147,7 @@ class ProfileControllerTest {
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.addProvider(new RateLimitExceededExceptionMapper()) .addProvider(new RateLimitExceededExceptionMapper())
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new ProfileController( .addResource(new ProfileController(
clock, clock,
@ -1392,7 +1392,7 @@ class ProfileControllerTest {
// `null` properties should be omitted from the response // `null` properties should be omitted from the response
assertThat(responseJson).doesNotContain("null"); assertThat(responseJson).doesNotContain("null");
BatchIdentityCheckResponse identityCheckResponse = SystemMapper.getMapper() BatchIdentityCheckResponse identityCheckResponse = SystemMapper.jsonMapper()
.readValue(responseJson, BatchIdentityCheckResponse.class); .readValue(responseJson, BatchIdentityCheckResponse.class);
assertThat(identityCheckResponse).isNotNull(); assertThat(identityCheckResponse).isNotNull();
assertThat(identityCheckResponse.elements()).isNotNull().hasSize(2); assertThat(identityCheckResponse.elements()).isNotNull().hasSize(2);

View File

@ -1,3 +1,8 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.controllers; package org.whispersystems.textsecuregcm.controllers;
import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertArrayEquals;
@ -50,7 +55,7 @@ class ProvisioningControllerTest {
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.addProvider(new RateLimitExceededExceptionMapper()) .addProvider(new RateLimitExceededExceptionMapper())
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new ProvisioningController(rateLimiters, provisioningManager)) .addResource(new ProvisioningController(rateLimiters, provisioningManager))
.build(); .build();

View File

@ -82,7 +82,7 @@ class RegistrationControllerTest {
.addProvider(new RateLimitExceededExceptionMapper()) .addProvider(new RateLimitExceededExceptionMapper())
.addProvider(new ImpossiblePhoneNumberExceptionMapper()) .addProvider(new ImpossiblePhoneNumberExceptionMapper())
.addProvider(new NonNormalizedPhoneNumberExceptionMapper()) .addProvider(new NonNormalizedPhoneNumberExceptionMapper())
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource( .addResource(
new RegistrationController(accountsManager, new RegistrationController(accountsManager,

View File

@ -68,7 +68,7 @@ class SecureBackupControllerTest {
private static final ResourceExtension RESOURCES = ResourceExtension.builder() private static final ResourceExtension RESOURCES = ResourceExtension.builder()
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(CONTROLLER) .addResource(CONTROLLER)
.build(); .build();

View File

@ -19,8 +19,7 @@ import static org.whispersystems.textsecuregcm.util.AttributeValues.b;
import static org.whispersystems.textsecuregcm.util.AttributeValues.n; import static org.whispersystems.textsecuregcm.util.AttributeValues.n;
import static org.whispersystems.textsecuregcm.util.AttributeValues.s; import static org.whispersystems.textsecuregcm.util.AttributeValues.s;
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.stripe.exception.ApiException; import com.stripe.exception.ApiException;
import com.stripe.model.PaymentIntent; import com.stripe.model.PaymentIntent;
import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider; import io.dropwizard.auth.PolymorphicAuthValueFactoryProvider;
@ -80,11 +79,7 @@ class SubscriptionControllerTest {
private static final Clock CLOCK = mock(Clock.class); private static final Clock CLOCK = mock(Clock.class);
private static final YAMLMapper YAML_MAPPER = new YAMLMapper(); private static final ObjectMapper YAML_MAPPER = SystemMapper.yamlMapper();
static {
YAML_MAPPER.registerModule(new JavaTimeModule());
}
private static final SubscriptionConfiguration SUBSCRIPTION_CONFIG = ConfigHelper.getSubscriptionConfig(); private static final SubscriptionConfiguration SUBSCRIPTION_CONFIG = ConfigHelper.getSubscriptionConfig();
private static final OneTimeDonationConfiguration ONETIME_CONFIG = ConfigHelper.getOneTimeConfig(); private static final OneTimeDonationConfiguration ONETIME_CONFIG = ConfigHelper.getOneTimeConfig();
@ -119,7 +114,7 @@ class SubscriptionControllerTest {
.addProvider(CompletionExceptionMapper.class) .addProvider(CompletionExceptionMapper.class)
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(Set.of( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(Set.of(
AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(SUBSCRIPTION_CONTROLLER) .addResource(SUBSCRIPTION_CONTROLLER)
.build(); .build();

View File

@ -92,7 +92,7 @@ class VerificationControllerTest {
.addProvider(new ImpossiblePhoneNumberExceptionMapper()) .addProvider(new ImpossiblePhoneNumberExceptionMapper())
.addProvider(new NonNormalizedPhoneNumberExceptionMapper()) .addProvider(new NonNormalizedPhoneNumberExceptionMapper())
.addProvider(new RegistrationServiceSenderExceptionMapper()) .addProvider(new RegistrationServiceSenderExceptionMapper())
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource( .addResource(
new VerificationController(registrationServiceClient, verificationSessionManager, pushNotificationManager, new VerificationController(registrationServiceClient, verificationSessionManager, pushNotificationManager,

View File

@ -5,13 +5,15 @@
package org.whispersystems.textsecuregcm.entities; package org.whispersystems.textsecuregcm.entities;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.exc.InvalidTypeIdException; import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.whispersystems.textsecuregcm.util.SystemMapper; import org.whispersystems.textsecuregcm.util.SystemMapper;
import static org.junit.jupiter.api.Assertions.*;
class AnswerChallengeRequestTest { class AnswerChallengeRequestTest {
@Test @Test
@ -25,7 +27,7 @@ class AnswerChallengeRequestTest {
"""; """;
final AnswerChallengeRequest answerChallengeRequest = final AnswerChallengeRequest answerChallengeRequest =
SystemMapper.getMapper().readValue(pushChallengeJson, AnswerChallengeRequest.class); SystemMapper.jsonMapper().readValue(pushChallengeJson, AnswerChallengeRequest.class);
assertTrue(answerChallengeRequest instanceof AnswerPushChallengeRequest); assertTrue(answerChallengeRequest instanceof AnswerPushChallengeRequest);
assertEquals("Hello I am a push challenge token", assertEquals("Hello I am a push challenge token",
@ -42,7 +44,7 @@ class AnswerChallengeRequestTest {
"""; """;
final AnswerChallengeRequest answerChallengeRequest = final AnswerChallengeRequest answerChallengeRequest =
SystemMapper.getMapper().readValue(recaptchaChallengeJson, AnswerChallengeRequest.class); SystemMapper.jsonMapper().readValue(recaptchaChallengeJson, AnswerChallengeRequest.class);
assertTrue(answerChallengeRequest instanceof AnswerRecaptchaChallengeRequest); assertTrue(answerChallengeRequest instanceof AnswerRecaptchaChallengeRequest);
@ -63,7 +65,7 @@ class AnswerChallengeRequestTest {
"""; """;
assertThrows(InvalidTypeIdException.class, assertThrows(InvalidTypeIdException.class,
() -> SystemMapper.getMapper().readValue(unrecognizedTypeJson, AnswerChallengeRequest.class)); () -> SystemMapper.jsonMapper().readValue(unrecognizedTypeJson, AnswerChallengeRequest.class));
} }
} }
} }

View File

@ -1,16 +1,17 @@
/* /*
* Copyright 2013-2022 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
package org.whispersystems.textsecuregcm.entities; package org.whispersystems.textsecuregcm.entities;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.whispersystems.textsecuregcm.util.SystemMapper; import org.whispersystems.textsecuregcm.util.SystemMapper;
import static org.junit.jupiter.api.Assertions.*;
class IncomingMessageListTest { class IncomingMessageListTest {
@Test @Test
@ -26,7 +27,7 @@ class IncomingMessageListTest {
"""; """;
final IncomingMessageList incomingMessageList = final IncomingMessageList incomingMessageList =
SystemMapper.getMapper().readValue(incomingMessageListJson, IncomingMessageList.class); SystemMapper.jsonMapper().readValue(incomingMessageListJson, IncomingMessageList.class);
assertTrue(incomingMessageList.online()); assertTrue(incomingMessageList.online());
assertFalse(incomingMessageList.urgent()); assertFalse(incomingMessageList.urgent());
@ -42,7 +43,7 @@ class IncomingMessageListTest {
"""; """;
final IncomingMessageList incomingMessageList = final IncomingMessageList incomingMessageList =
SystemMapper.getMapper().readValue(incomingMessageListJson, IncomingMessageList.class); SystemMapper.jsonMapper().readValue(incomingMessageListJson, IncomingMessageList.class);
assertTrue(incomingMessageList.online()); assertTrue(incomingMessageList.online());
assertTrue(incomingMessageList.urgent()); assertTrue(incomingMessageList.urgent());

View File

@ -15,6 +15,7 @@ import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.whispersystems.textsecuregcm.util.SystemMapper;
class LeakyBucketTest { class LeakyBucketTest {
@ -35,7 +36,7 @@ class LeakyBucketTest {
@Test @Test
void testLapseRate() throws IOException { void testLapseRate() throws IOException {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = SystemMapper.jsonMapper();
String serialized = "{\"bucketSize\":2,\"leakRatePerMillis\":8.333333333333334E-6,\"spaceRemaining\":0,\"lastUpdateTimeMillis\":" + (System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(2)) + "}"; String serialized = "{\"bucketSize\":2,\"leakRatePerMillis\":8.333333333333334E-6,\"spaceRemaining\":0,\"lastUpdateTimeMillis\":" + (System.currentTimeMillis() - TimeUnit.MINUTES.toMillis(2)) + "}";
LeakyBucket leakyBucket = LeakyBucket.fromSerialized(mapper, serialized); LeakyBucket leakyBucket = LeakyBucket.fromSerialized(mapper, serialized);

View File

@ -61,7 +61,7 @@ public class RateLimitedByIpTest {
Mockito.when(rl.forDescriptor(Mockito.eq(RateLimiters.For.BACKUP_AUTH_CHECK))).thenReturn(RATE_LIMITER)); Mockito.when(rl.forDescriptor(Mockito.eq(RateLimiters.For.BACKUP_AUTH_CHECK))).thenReturn(RATE_LIMITER));
private static final ResourceExtension RESOURCES = ResourceExtension.builder() private static final ResourceExtension RESOURCES = ResourceExtension.builder()
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new Controller()) .addResource(new Controller())
.addProvider(new RateLimitByIpFilter(RATE_LIMITERS)) .addProvider(new RateLimitByIpFilter(RATE_LIMITERS))

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2022 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -271,7 +271,7 @@ class AccountsTest {
.item(Map.of( .item(Map.of(
Accounts.KEY_ACCOUNT_UUID, AttributeValues.fromUUID(uuid), Accounts.KEY_ACCOUNT_UUID, AttributeValues.fromUUID(uuid),
Accounts.ATTR_ACCOUNT_E164, AttributeValues.fromString(account.getNumber()), Accounts.ATTR_ACCOUNT_E164, AttributeValues.fromString(account.getNumber()),
Accounts.ATTR_ACCOUNT_DATA, AttributeValues.fromByteArray(SystemMapper.getMapper().writeValueAsBytes(account)), Accounts.ATTR_ACCOUNT_DATA, AttributeValues.fromByteArray(SystemMapper.jsonMapper().writeValueAsBytes(account)),
Accounts.ATTR_VERSION, AttributeValues.fromInt(account.getVersion()), Accounts.ATTR_VERSION, AttributeValues.fromInt(account.getVersion()),
Accounts.ATTR_CANONICALLY_DISCOVERABLE, AttributeValues.fromBool(account.shouldBeVisibleInDirectory()))) Accounts.ATTR_CANONICALLY_DISCOVERABLE, AttributeValues.fromBool(account.shouldBeVisibleInDirectory())))
.build()) .build())

View File

@ -46,7 +46,7 @@ class ArtControllerTest {
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new ArtController(rateLimiters, artCredentialsGenerator)) .addResource(new ArtController(rateLimiters, artCredentialsGenerator))
.build(); .build();

View File

@ -77,7 +77,7 @@ class AttachmentControllerTest {
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new AttachmentControllerV2(RATE_LIMITERS, "accessKey", "accessSecret", "us-east-1", "attachmentv2-bucket")) .addResource(new AttachmentControllerV2(RATE_LIMITERS, "accessKey", "accessSecret", "us-east-1", "attachmentv2-bucket"))
.addResource(new AttachmentControllerV3(RATE_LIMITERS, "some-cdn.signal.org", "signal@example.com", 1000, "/attach-here", RSA_PRIVATE_KEY_PEM)) .addResource(new AttachmentControllerV3(RATE_LIMITERS, "some-cdn.signal.org", "signal@example.com", 1000, "/attach-here", RSA_PRIVATE_KEY_PEM))

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2021 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -84,7 +84,7 @@ class CertificateControllerTest {
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new CertificateController(certificateGenerator, serverZkAuthOperations, clock)) .addResource(new CertificateController(certificateGenerator, serverZkAuthOperations, clock))
.build(); .build();

View File

@ -40,7 +40,7 @@ class SecureStorageControllerTest {
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new SecureStorageController(STORAGE_CREDENTIAL_GENERATOR)) .addResource(new SecureStorageController(STORAGE_CREDENTIAL_GENERATOR))
.build(); .build();

View File

@ -41,7 +41,7 @@ class StickerControllerTest {
.addProvider(AuthHelper.getAuthFilter()) .addProvider(AuthHelper.getAuthFilter())
.addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>( .addProvider(new PolymorphicAuthValueFactoryProvider.Binder<>(
ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class))) ImmutableSet.of(AuthenticatedAccount.class, DisabledPermittedAuthenticatedAccount.class)))
.setMapper(SystemMapper.getMapper()) .setMapper(SystemMapper.jsonMapper())
.setTestContainerFactory(new GrizzlyWebTestContainerFactory()) .setTestContainerFactory(new GrizzlyWebTestContainerFactory())
.addResource(new StickerController(rateLimiters, "foo", "bar", "us-east-1", "mybucket")) .addResource(new StickerController(rateLimiters, "foo", "bar", "us-east-1", "mybucket"))
.build(); .build();

View File

@ -137,7 +137,7 @@ public class AccountsHelper {
} }
} else { } else {
final ObjectMapper mapper = SystemMapper.getMapper(); final ObjectMapper mapper = SystemMapper.jsonMapper();
updatedAccount = mapper.readValue(mapper.writeValueAsBytes(account), Account.class); updatedAccount = mapper.readValue(mapper.writeValueAsBytes(account), Account.class);
updatedAccount.setNumber(account.getNumber(), account.getPhoneNumberIdentifier()); updatedAccount.setNumber(account.getNumber(), account.getPhoneNumberIdentifier());
account.markStale(); account.markStale();

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2020 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -15,7 +15,7 @@ import org.whispersystems.textsecuregcm.util.SystemMapper;
public class JsonHelpers { public class JsonHelpers {
private static final ObjectMapper objectMapper = SystemMapper.getMapper(); private static final ObjectMapper objectMapper = SystemMapper.jsonMapper();
public static String asJson(Object object) throws JsonProcessingException { public static String asJson(Object object) throws JsonProcessingException {
return objectMapper.writeValueAsString(object); return objectMapper.writeValueAsString(object);

View File

@ -0,0 +1,99 @@
/*
* Copyright 2023 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/
package org.whispersystems.textsecuregcm.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
class SystemMapperTest {
private static final ObjectMapper MAPPER = SystemMapper.configureMapper(new ObjectMapper());
private static final String JSON_NO_FIELD = """
{}
""".trim();
private static final String JSON_NULL_FIELD = """
{"name":null}
""".trim();
private static final String JSON_WITH_FIELD = """
{"name":"value"}
""".trim();
interface Data {
Optional<String> name();
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public record DataRecord(Optional<String> name) implements Data {
}
public static class DataClass implements Data {
@JsonProperty
private Optional<String> name = Optional.empty();
public DataClass() {
}
public DataClass(final Optional<String> name) {
this.name = name;
}
@Override
public Optional<String> name() {
return name;
}
}
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public static class DataClass2 extends DataClass {
public DataClass2(final Optional<String> name) {
super(name);
}
}
@ParameterizedTest
@ValueSource(classes = {DataClass.class, DataRecord.class})
public void testOptionalField(final Class<? extends Data> clazz) throws Exception {
assertTrue(MAPPER.readValue(JSON_NO_FIELD, clazz).name().isEmpty());
assertTrue(MAPPER.readValue(JSON_NULL_FIELD, clazz).name().isEmpty());
assertEquals("value", MAPPER.readValue(JSON_WITH_FIELD, clazz).name().orElseThrow());
}
@ParameterizedTest
@MethodSource("provideStringsForIsBlank")
public void testSerialization(final Data data, final String expectedJson) throws Exception {
assertEquals(expectedJson, MAPPER.writeValueAsString(data));
}
private static Stream<Arguments> provideStringsForIsBlank() {
return Stream.of(
Arguments.of(new DataClass(Optional.of("value")), JSON_WITH_FIELD),
Arguments.of(new DataClass(Optional.empty()), JSON_NULL_FIELD),
Arguments.of(new DataClass(null), JSON_NULL_FIELD),
Arguments.of(new DataClass2(Optional.of("value")), JSON_WITH_FIELD),
Arguments.of(new DataClass2(Optional.of("value")), JSON_WITH_FIELD),
Arguments.of(new DataClass2(Optional.empty()), JSON_NO_FIELD),
Arguments.of(new DataRecord(Optional.of("value")), JSON_WITH_FIELD),
Arguments.of(new DataRecord(Optional.empty()), JSON_NO_FIELD),
Arguments.of(new DataRecord(null), JSON_NO_FIELD)
);
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2021 Signal Messenger, LLC * Copyright 2013 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only * SPDX-License-Identifier: AGPL-3.0-only
*/ */
@ -15,7 +15,6 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.net.HttpHeaders; import com.google.common.net.HttpHeaders;
import io.dropwizard.jersey.DropwizardResourceConfig; import io.dropwizard.jersey.DropwizardResourceConfig;
import io.dropwizard.jersey.jackson.JacksonMessageBodyProvider; import io.dropwizard.jersey.jackson.JacksonMessageBodyProvider;
@ -43,6 +42,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.whispersystems.textsecuregcm.util.SystemMapper;
import org.whispersystems.websocket.WebSocketResourceProvider; import org.whispersystems.websocket.WebSocketResourceProvider;
import org.whispersystems.websocket.auth.WebsocketAuthValueFactoryProvider; import org.whispersystems.websocket.auth.WebsocketAuthValueFactoryProvider;
import org.whispersystems.websocket.logging.WebsocketRequestLog; import org.whispersystems.websocket.logging.WebsocketRequestLog;
@ -129,7 +129,7 @@ class LoggingUnhandledExceptionMapperTest {
resourceConfig.register(new TestController()); resourceConfig.register(new TestController());
resourceConfig.register(new WebSocketSessionContextValueFactoryProvider.Binder()); resourceConfig.register(new WebSocketSessionContextValueFactoryProvider.Binder());
resourceConfig.register(new WebsocketAuthValueFactoryProvider.Binder<>(TestPrincipal.class)); resourceConfig.register(new WebsocketAuthValueFactoryProvider.Binder<>(TestPrincipal.class));
resourceConfig.register(new JacksonMessageBodyProvider(new ObjectMapper())); resourceConfig.register(new JacksonMessageBodyProvider(SystemMapper.jsonMapper()));
ApplicationHandler applicationHandler = new ApplicationHandler(resourceConfig); ApplicationHandler applicationHandler = new ApplicationHandler(resourceConfig);
WebsocketRequestLog requestLog = mock(WebsocketRequestLog.class); WebsocketRequestLog requestLog = mock(WebsocketRequestLog.class);