Skip to content
This repository has been archived by the owner on Nov 22, 2023. It is now read-only.

Commit

Permalink
Wrap OffsetDateTime in ApiDate & update Jackson.
Browse files Browse the repository at this point in the history
Changes:

Update Jackson to the newest stable release (2.6.1).

We wrap OffsetDateTime in an ApiDate that provides a thin wrapper around it
and custom Json de/serializers.  It also has static now() and parse() methods
that are heavily used in tests, and equality & hashcode checks implented in the
obvious way.

There's a lot of mundane changes to pipe the type throughout the API, and to
update tests appropriately.

Remove the now unused options to set up the date format in Jackson: This makes
it easier to find buggy serialization, as they get written as a number instead.

- Background & Alternatives:

Keywhiz uses Jackson for JSON de/serialization.  When OffsetDateTime is
serialized with Jackson's JSR310 module, which omits the milliseconds if
they're all zero.  While this is unlikely to happen, as most times in the
keywhiz world are timestamps and the milliseconds are effectively random, it
does make Keywhiz-fs unhappy, and unable to list secrets, or read the secret
with the unsupported date format.

We set the jackson date format explicitly, but that's a red herring: The JSR310
date module doesn't use this.  We could explicitly set the pattern with
@JsonPattern to be yyyy-MM-dd'T'mm-HH-ss.SSS'Z' which serializes dates properly,
but then won't deserialize because OffsetDateTime's constructor doesn't know
what timezone it's in.  If we used the unquoted 'Z', the timezone will serialize
as +0000, which is undesired too, but it deserializes properly.

We could load a custom module into Jackson that provides custom de/serializers
for OffsetDateTime, but we need to load the Jdk8 module, which provides
conflicting de/serializers for OffsetDateTime.  You could probably get that to
work with the right ordering, but that feels awfully fragile to me (and I
didn't get it to work).
  • Loading branch information
mcpherrinm committed Oct 20, 2015
1 parent c412714 commit 9c33fdf
Show file tree
Hide file tree
Showing 54 changed files with 285 additions and 159 deletions.
86 changes: 86 additions & 0 deletions api/src/main/java/keywhiz/api/ApiDate.java
@@ -0,0 +1,86 @@
/*
* Copyright (C) 2015 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package keywhiz.api;

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;

/**
* This is a wrapper for the date class used in API responses so we can have a custom JSON serializer and deserializer
*/
@JsonSerialize(using=ApiDate.ApiDateSerializer.class)
@JsonDeserialize(using=ApiDate.ApiDateDeserializer.class)
public class ApiDate {

static class ApiDateSerializer extends JsonSerializer<ApiDate> {
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
@Override
public void serialize(ApiDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
gen.writeString(formatter.format(value.offsetDateTime));
}
}

static class ApiDateDeserializer extends JsonDeserializer<ApiDate> {
@Override
public ApiDate deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
return new ApiDate(parser.readValueAs(OffsetDateTime.class));
}
}

public static ApiDate parse(String s) {
return new ApiDate(OffsetDateTime.parse(s));
}

public static ApiDate now() {
return new ApiDate(OffsetDateTime.now());
}

public long toEpochSecond() {
return this.offsetDateTime.toEpochSecond();
}

@Override
public boolean equals(Object obj) {
if (obj instanceof ApiDate) {
ApiDate that = (ApiDate) obj;
return this.offsetDateTime.equals(that.offsetDateTime);
}
return false;
}

@Override
public int hashCode() {
return this.offsetDateTime.hashCode();
}

public ApiDate(OffsetDateTime odt) {
this.offsetDateTime = odt;
}

public OffsetDateTime offsetDateTime;
}

4 changes: 2 additions & 2 deletions api/src/main/java/keywhiz/api/AutomationSecretResponse.java
Expand Up @@ -38,7 +38,7 @@
public abstract class AutomationSecretResponse {

public static AutomationSecretResponse create(long id, String name, String secret,
OffsetDateTime creationDate, boolean isVersioned,
ApiDate creationDate, boolean isVersioned,
ImmutableMap<String, String> metadata, ImmutableList<Group> groups) {
return new AutoValue_AutomationSecretResponse(id, name, secret, decodedLength(secret),
creationDate, isVersioned, groups, metadata);
Expand All @@ -60,7 +60,7 @@ public static AutomationSecretResponse fromSecret(Secret secret, ImmutableList<G
@JsonProperty("name") public abstract String name();
@JsonProperty("secret") public abstract String secret();
@JsonProperty("secretLength") public abstract long secretLength();
@JsonProperty("creationDate") public abstract OffsetDateTime creationDate();
@JsonProperty("creationDate") public abstract ApiDate creationDate();
@JsonProperty("isVersioned") public abstract boolean isVersioned();
@JsonProperty("groups") public abstract ImmutableList<Group> groups();
@JsonAnyGetter @JsonProperty("metadata") public abstract Map<String, String> metadata();
Expand Down
8 changes: 4 additions & 4 deletions api/src/main/java/keywhiz/api/ClientDetailResponse.java
Expand Up @@ -34,10 +34,10 @@ public class ClientDetailResponse {
public final String description;

@JsonProperty
public final OffsetDateTime creationDate;
public final ApiDate creationDate;

@JsonProperty
public final OffsetDateTime updateDate;
public final ApiDate updateDate;

@JsonProperty
public final String createdBy;
Expand All @@ -55,8 +55,8 @@ public class ClientDetailResponse {
public ClientDetailResponse(@JsonProperty("id") long id,
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("creationDate") OffsetDateTime creationDate,
@JsonProperty("updateDate") OffsetDateTime updateDate,
@JsonProperty("creationDate") ApiDate creationDate,
@JsonProperty("updateDate") ApiDate updateDate,
@JsonProperty("createdBy") String createdBy,
@JsonProperty("updatedBy") String updatedBy,
@JsonProperty("groups") ImmutableList<Group> groups,
Expand Down
12 changes: 6 additions & 6 deletions api/src/main/java/keywhiz/api/GroupDetailResponse.java
Expand Up @@ -36,10 +36,10 @@ public class GroupDetailResponse {
private final String description;

@JsonProperty
private final OffsetDateTime creationDate;
private final ApiDate creationDate;

@JsonProperty
private final OffsetDateTime updateDate;
private final ApiDate updateDate;

@JsonProperty
private final String createdBy;
Expand All @@ -56,8 +56,8 @@ public class GroupDetailResponse {
public GroupDetailResponse(@JsonProperty("id") long id,
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("creationDate") OffsetDateTime creationDate,
@JsonProperty("updateDate") OffsetDateTime updateDate,
@JsonProperty("creationDate") ApiDate creationDate,
@JsonProperty("updateDate") ApiDate updateDate,
@JsonProperty("createdBy") String createdBy,
@JsonProperty("updatedBy") String updatedBy,
@JsonProperty("secrets") ImmutableList<SanitizedSecret> secrets,
Expand Down Expand Up @@ -98,11 +98,11 @@ public String getDescription() {
return description;
}

public OffsetDateTime getCreationDate() {
public ApiDate getCreationDate() {
return creationDate;
}

public OffsetDateTime getUpdateDate() {
public ApiDate getUpdateDate() {
return updateDate;
}

Expand Down
6 changes: 3 additions & 3 deletions api/src/main/java/keywhiz/api/SecretDeliveryResponse.java
Expand Up @@ -34,15 +34,15 @@ public class SecretDeliveryResponse {
private final String name;
private final String secret;
private final int secretLength;
private final OffsetDateTime creationDate;
private final ApiDate creationDate;
private final boolean isVersioned;
private final ImmutableMap<String, String> metadata;

public SecretDeliveryResponse(
@JsonProperty("name") String name,
@JsonProperty("secret") String secret,
@JsonProperty("secretLength") int secretLength,
@JsonProperty("creationDate") OffsetDateTime creationDate,
@JsonProperty("creationDate") ApiDate creationDate,
@JsonProperty("isVersioned") boolean isVersioned,
@JsonProperty("metadata") ImmutableMap<String, String> metadata) {
this.name = name;
Expand Down Expand Up @@ -89,7 +89,7 @@ public int getSecretLength() {
}

/** @return ISO-8601 datetime the secret was created. */
public OffsetDateTime getCreationDate() {
public ApiDate getCreationDate() {
return creationDate;
}

Expand Down
8 changes: 4 additions & 4 deletions api/src/main/java/keywhiz/api/SecretDetailResponse.java
Expand Up @@ -37,15 +37,15 @@ public class SecretDetailResponse {
public final String description;

@JsonProperty
public final OffsetDateTime createdAt;
public final ApiDate createdAt;

/** User who created the record. */
@JsonProperty
public final String createdBy;

/** Should equal createdAt, but added for consistency in the API. */
@JsonProperty
public final OffsetDateTime updatedAt;
public final ApiDate updatedAt;

/** User who updated the record. */
@JsonProperty
Expand All @@ -67,9 +67,9 @@ public class SecretDetailResponse {
public SecretDetailResponse(@JsonProperty("id") long id,
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("createdAt") OffsetDateTime createdAt,
@JsonProperty("createdAt") ApiDate createdAt,
@JsonProperty("createdBy") String createdBy,
@JsonProperty("updatedAt") OffsetDateTime updatedAt,
@JsonProperty("updatedAt") ApiDate updatedAt,
@JsonProperty("updatedBy") String updatedBy,
@JsonProperty("isVersioned") boolean versioned,
@JsonProperty("metadata") ImmutableMap<String, String> metadata,
Expand Down
Expand Up @@ -11,6 +11,7 @@
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;

import keywhiz.api.model.Secret;
import keywhiz.api.model.SecretSeries;

Expand Down
14 changes: 8 additions & 6 deletions api/src/main/java/keywhiz/api/model/Client.java
Expand Up @@ -19,6 +19,8 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import keywhiz.api.ApiDate;

import java.time.OffsetDateTime;
import javax.annotation.Nullable;

Expand All @@ -37,13 +39,13 @@ public class Client {
private final String description;

@JsonProperty
private final OffsetDateTime createdAt;
private final ApiDate createdAt;

@JsonProperty
private final String createdBy;

@JsonProperty
private final OffsetDateTime updatedAt;
private final ApiDate updatedAt;

@JsonProperty
private final String updatedBy;
Expand All @@ -59,9 +61,9 @@ public class Client {
public Client(@JsonProperty("id") long id,
@JsonProperty("name") String name,
@JsonProperty("description") @Nullable String description,
@JsonProperty("createdAt") OffsetDateTime createdAt,
@JsonProperty("createdAt") ApiDate createdAt,
@JsonProperty("createdBy") @Nullable String createdBy,
@JsonProperty("updatedAt") OffsetDateTime updatedAt,
@JsonProperty("updatedAt") ApiDate updatedAt,
@JsonProperty("updatedBy") @Nullable String updatedBy,
@JsonProperty("enabled") boolean enabled,
@JsonProperty("automationAllowed") boolean automationAllowed) {
Expand All @@ -88,15 +90,15 @@ public String getDescription() {
return description;
}

public OffsetDateTime getCreatedAt() {
public ApiDate getCreatedAt() {
return createdAt;
}

public String getCreatedBy() {
return createdBy;
}

public OffsetDateTime getUpdatedAt() {
public ApiDate getUpdatedAt() {
return updatedAt;
}

Expand Down
16 changes: 8 additions & 8 deletions api/src/main/java/keywhiz/api/model/Group.java
Expand Up @@ -18,6 +18,8 @@
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import keywhiz.api.ApiDate;

import java.time.OffsetDateTime;
import javax.annotation.Nullable;

Expand All @@ -39,23 +41,23 @@ public class Group {
private final String description;

@JsonProperty
private final OffsetDateTime createdAt;
private final ApiDate createdAt;

@JsonProperty
private final String createdBy;

@JsonProperty
private final OffsetDateTime updatedAt;
private final ApiDate updatedAt;

@JsonProperty
private final String updatedBy;

public Group(@JsonProperty("id") long id,
@JsonProperty("name") String name,
@JsonProperty("description") @Nullable String description,
@JsonProperty("createdAt") OffsetDateTime createdAt,
@JsonProperty("createdAt") ApiDate createdAt,
@JsonProperty("createdBy") @Nullable String createdBy,
@JsonProperty("updatedAt") OffsetDateTime updatedAt,
@JsonProperty("updatedAt") ApiDate updatedAt,
@JsonProperty("updatedBy") @Nullable String updatedBy) {
this.id = id;
this.name = checkNotNull(name);
Expand All @@ -78,15 +80,13 @@ public String getDescription() {
return description;
}

public OffsetDateTime getCreatedAt() {
return createdAt;
}
public ApiDate getCreatedAt() { return createdAt; }

public String getCreatedBy() {
return createdBy;
}

public OffsetDateTime getUpdatedAt() {
public ApiDate getUpdatedAt() {
return updatedAt;
}

Expand Down
10 changes: 6 additions & 4 deletions api/src/main/java/keywhiz/api/model/SanitizedSecret.java
Expand Up @@ -21,6 +21,8 @@
import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import keywhiz.api.ApiDate;

import java.time.OffsetDateTime;
import java.util.List;
import java.util.Map;
Expand All @@ -40,9 +42,9 @@ public abstract class SanitizedSecret {
@JsonProperty("name") String name,
@JsonProperty("version") String version,
@JsonProperty("description") @Nullable String description,
@JsonProperty("createdAt") OffsetDateTime createdAt,
@JsonProperty("createdAt") ApiDate createdAt,
@JsonProperty("createdBy") @Nullable String createdBy,
@JsonProperty("updatedAt") OffsetDateTime updatedAt,
@JsonProperty("updatedAt") ApiDate updatedAt,
@JsonProperty("updatedBy") @Nullable String updatedBy,
@JsonProperty("metadata") @Nullable Map<String, String> metadata,
@JsonProperty("type") @Nullable String type,
Expand Down Expand Up @@ -111,9 +113,9 @@ public static List<SanitizedSecret> fromSecrets(List<Secret> secrets) {
@JsonProperty public abstract String name();
@JsonProperty public abstract String version();
@JsonProperty public abstract String description();
@JsonProperty public abstract OffsetDateTime createdAt();
@JsonProperty public abstract ApiDate createdAt();
@JsonProperty public abstract String createdBy();
@JsonProperty public abstract OffsetDateTime updatedAt();
@JsonProperty public abstract ApiDate updatedAt();
@JsonProperty public abstract String updatedBy();
@JsonProperty public abstract ImmutableMap<String, String> metadata();
@JsonProperty public abstract Optional<String> type();
Expand Down

0 comments on commit 9c33fdf

Please sign in to comment.