Skip to content

Commit 43e623f

Browse files
committed
WIP SB 4.0.0
1 parent f1ac044 commit 43e623f

File tree

10 files changed

+624
-6
lines changed

10 files changed

+624
-6
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.faforever.api.data.jackson3compat;
2+
3+
import com.yahoo.elide.core.dictionary.RelationshipType;
4+
import com.yahoo.elide.jsonapi.models.ResourceIdentifier;
5+
import lombok.ToString;
6+
import reactor.core.publisher.Flux;
7+
import tools.jackson.databind.annotation.JsonDeserialize;
8+
import tools.jackson.databind.annotation.JsonSerialize;
9+
10+
import java.util.Collection;
11+
import java.util.Comparator;
12+
13+
@JsonSerialize(using = DataSerializer.class)
14+
@JsonDeserialize(using = DataDeserializer.class)
15+
@ToString
16+
public class Data<T> {
17+
private Flux<T> values;
18+
private final RelationshipType relationshipType;
19+
20+
/**
21+
* Constructor.
22+
*
23+
* @param value singleton resource
24+
*/
25+
public Data(T value) {
26+
if (value == null) {
27+
this.values = Flux.empty();
28+
} else {
29+
this.values = Flux.just(value);
30+
}
31+
this.relationshipType = RelationshipType.MANY_TO_ONE; // Any "toOne"
32+
}
33+
34+
/**
35+
* Constructor.
36+
*
37+
* @param values List of resources
38+
*/
39+
public Data(Flux<T> values) {
40+
this(values, RelationshipType.MANY_TO_MANY);
41+
}
42+
43+
/**
44+
* Constructor.
45+
*
46+
* @param values List of resources
47+
* @param relationshipType toOne or toMany
48+
*/
49+
public Data(Flux<T> values, RelationshipType relationshipType) {
50+
this.values = values;
51+
this.relationshipType = relationshipType;
52+
}
53+
54+
/**
55+
* Constructor.
56+
*
57+
* @param values List of resources
58+
*/
59+
public Data(Collection<T> values) {
60+
this(values, RelationshipType.MANY_TO_MANY);
61+
}
62+
63+
/**
64+
* Constructor.
65+
*
66+
* @param values List of resources
67+
* @param relationshipType toOne or toMany
68+
*/
69+
public Data(Collection<T> values, RelationshipType relationshipType) {
70+
this.values = Flux.fromIterable(values);
71+
this.relationshipType = relationshipType;
72+
}
73+
74+
/**
75+
* Sort method using provided sort function.
76+
*
77+
* @param sortFunction comparator to sort data with
78+
*/
79+
public void sort(Comparator<T> sortFunction) {
80+
this.values = this.values.sort(sortFunction);
81+
}
82+
83+
/**
84+
* Fetches the resources.
85+
*
86+
* @return the resources
87+
*/
88+
public Collection<T> get() {
89+
return values.collectList().block();
90+
}
91+
92+
/**
93+
* Determine whether or not the contained type is toOne.
94+
*
95+
* @return True if toOne, false if toMany
96+
*/
97+
public boolean isToOne() {
98+
return relationshipType.isToOne();
99+
}
100+
101+
/**
102+
* Fetch the item if the data is toOne.
103+
*
104+
* @return T if toOne
105+
* @throws IllegalAccessError when the data is not toOne
106+
*/
107+
public T getSingleValue() {
108+
if (isToOne()) {
109+
return values.singleOrEmpty().block();
110+
}
111+
112+
throw new IllegalAccessError("Data is not toOne");
113+
}
114+
115+
/**
116+
* Gets the resource identifiers.
117+
*
118+
* @return the resource identifiers
119+
*/
120+
public Collection<ResourceIdentifier> toResourceIdentifiers() {
121+
return values
122+
.map(object -> object != null ? ((Resource) object).toResourceIdentifier() : null)
123+
.collectList().block();
124+
}
125+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2015, Yahoo Inc.
3+
* Licensed under the Apache License, Version 2.0
4+
* See LICENSE file in project root for terms.
5+
*/
6+
package com.faforever.api.data.jackson3compat;
7+
8+
import tools.jackson.core.JacksonException;
9+
import tools.jackson.core.JsonParser;
10+
import tools.jackson.databind.DatabindException;
11+
import tools.jackson.databind.DeserializationContext;
12+
import tools.jackson.databind.JsonNode;
13+
import tools.jackson.databind.ValueDeserializer;
14+
15+
import java.util.ArrayList;
16+
import java.util.List;
17+
18+
/**
19+
* Custom deserializer for top-level data.
20+
*/
21+
public class DataDeserializer extends ValueDeserializer<Data<Resource>> {
22+
23+
@Override
24+
public Data<Resource> deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws JacksonException {
25+
JsonNode node = jsonParser.readValueAsTree();
26+
if (node.isArray()) {
27+
List<Resource> resources = new ArrayList<>();
28+
for (JsonNode n : node) {
29+
Resource r = deserializationContext.readTreeAsValue(n, Resource.class);
30+
validateResource(jsonParser, r);
31+
resources.add(r);
32+
}
33+
return new Data<>(resources);
34+
}
35+
Resource resource = deserializationContext.readTreeAsValue(node, Resource.class);
36+
validateResource(jsonParser, resource);
37+
return new Data<>(resource);
38+
}
39+
40+
private void validateResource(JsonParser jsonParser, Resource resource) {
41+
if (resource.getType() == null || resource.getType().isEmpty()) {
42+
throw DatabindException.from(jsonParser, "Resource 'type' field is missing or empty.");
43+
}
44+
}
45+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2015, Yahoo Inc.
3+
* Licensed under the Apache License, Version 2.0
4+
* See LICENSE file in project root for terms.
5+
*/
6+
package com.faforever.api.data.jackson3compat;
7+
8+
import org.apache.commons.collections4.CollectionUtils;
9+
import org.apache.commons.collections4.IterableUtils;
10+
import tools.jackson.core.JacksonException;
11+
import tools.jackson.core.JsonGenerator;
12+
import tools.jackson.databind.SerializationContext;
13+
import tools.jackson.databind.ValueSerializer;
14+
15+
import java.util.Collection;
16+
import java.util.Collections;
17+
18+
/**
19+
* Custom serializer for top-level data.
20+
*/
21+
public class DataSerializer extends ValueSerializer<Data<Resource>> {
22+
23+
@Override
24+
public void serialize(Data<Resource> data, JsonGenerator jsonGenerator, SerializationContext ctxt) throws JacksonException {
25+
Collection<Resource> list = data.get();
26+
if (data.isToOne()) {
27+
if (CollectionUtils.isEmpty(list)) {
28+
jsonGenerator.writePOJO(null);
29+
return;
30+
}
31+
jsonGenerator.writePOJO(IterableUtils.first(list));
32+
return;
33+
}
34+
jsonGenerator.writePOJO((list == null) ? Collections.emptyList() : list);
35+
}
36+
}
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*
2+
* Copyright 2015, Yahoo Inc.
3+
* Licensed under the Apache License, Version 2.0
4+
* See LICENSE file in project root for terms.
5+
*/
6+
package com.faforever.api.data.jackson3compat;
7+
8+
import com.fasterxml.jackson.annotation.JsonInclude;
9+
import lombok.ToString;
10+
import org.apache.commons.lang3.builder.HashCodeBuilder;
11+
12+
import java.util.ArrayList;
13+
import java.util.Collection;
14+
import java.util.Collections;
15+
import java.util.LinkedHashMap;
16+
import java.util.LinkedHashSet;
17+
import java.util.List;
18+
import java.util.Map;
19+
import java.util.Optional;
20+
21+
/**
22+
* JSON API Document.
23+
*/
24+
@ToString
25+
public class JsonApiDocument {
26+
private Data<Resource> data;
27+
private Meta meta;
28+
private final Map<String, String> links;
29+
private final LinkedHashSet<Resource> includedRecs;
30+
private final List<Resource> included;
31+
32+
public JsonApiDocument() {
33+
this(null);
34+
}
35+
36+
public JsonApiDocument(Data<Resource> data) {
37+
links = new LinkedHashMap<>();
38+
included = new ArrayList<>();
39+
includedRecs = new LinkedHashSet<>();
40+
this.data = data;
41+
}
42+
43+
public void setData(Data<Resource> data) {
44+
this.data = data;
45+
}
46+
47+
public Data<Resource> getData() {
48+
return data;
49+
}
50+
51+
public void setMeta(Meta meta) {
52+
this.meta = meta;
53+
}
54+
55+
@JsonInclude(JsonInclude.Include.NON_NULL)
56+
public Meta getMeta() {
57+
return meta;
58+
}
59+
60+
@JsonInclude(JsonInclude.Include.NON_NULL)
61+
public Map<String, String> getLinks() {
62+
return links.isEmpty() ? null : links;
63+
}
64+
65+
public void addLink(String key, String val) {
66+
this.links.put(key, val);
67+
}
68+
69+
@JsonInclude(JsonInclude.Include.NON_NULL)
70+
public List<Resource> getIncluded() {
71+
return included.isEmpty() ? null : included;
72+
}
73+
74+
public void addIncluded(Resource resource) {
75+
if (!includedRecs.contains(resource)) {
76+
included.add(resource);
77+
includedRecs.add(resource);
78+
}
79+
}
80+
81+
@Override
82+
public int hashCode() {
83+
Collection<Resource> resources = data == null ? null : data.get();
84+
return new HashCodeBuilder(37, 79)
85+
.append(resources == null ? 0 : resources.stream().mapToInt(Object::hashCode).sum())
86+
.append(links)
87+
.append(included == null ? 0 : included.stream().mapToInt(Object::hashCode).sum())
88+
.build();
89+
}
90+
91+
@Override
92+
public boolean equals(Object obj) {
93+
if (!(obj instanceof JsonApiDocument)) {
94+
return false;
95+
}
96+
JsonApiDocument other = (JsonApiDocument) obj;
97+
Collection<Resource> resources = Optional.ofNullable(data).map(Data::get).orElseGet(Collections::emptySet);
98+
Collection<Resource> otherResources =
99+
Optional.ofNullable(other.data).map(Data::get).orElseGet(Collections::emptySet);
100+
101+
if (resources.size() != otherResources.size() || !resources.stream().allMatch(otherResources::contains)) {
102+
return false;
103+
}
104+
// TODO: Verify links and meta?
105+
if (other.getIncluded() == null) {
106+
return included.isEmpty();
107+
}
108+
return included.stream().allMatch(other.getIncluded()::contains);
109+
}
110+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright 2016, Yahoo Inc.
3+
* Licensed under the Apache License, Version 2.0
4+
* See LICENSE file in project root for terms.
5+
*/
6+
package com.faforever.api.data.jackson3compat;
7+
8+
import tools.jackson.core.JacksonException;
9+
import tools.jackson.core.JsonGenerator;
10+
import tools.jackson.databind.SerializationContext;
11+
import tools.jackson.databind.ser.std.StdSerializer;
12+
13+
import java.util.Date;
14+
15+
/**
16+
* Custom serializer for Serializing Map Keys.
17+
* Change from StdKeySerializer - In cases of enum value it uses
18+
* name() instead of defaulting to toString() since that may be overridden
19+
*/
20+
public class KeySerializer extends StdSerializer<Object> {
21+
22+
protected KeySerializer() {
23+
super(Object.class);
24+
}
25+
26+
@Override
27+
public void serialize(Object value, JsonGenerator jgen, SerializationContext provider) throws JacksonException {
28+
String str;
29+
Class<?> cls = value.getClass();
30+
31+
if (cls == String.class) {
32+
str = (String) value;
33+
} else if (Date.class.isAssignableFrom(cls)) {
34+
provider.defaultSerializeDateKey((Date) value, jgen);
35+
return;
36+
} else if (cls == Class.class) {
37+
str = ((Class<?>) value).getName();
38+
} else if (cls.isEnum()) {
39+
str = ((Enum<?>) value).name();
40+
} else {
41+
str = value.toString();
42+
}
43+
jgen.writeName(str);
44+
}
45+
}

0 commit comments

Comments
 (0)