io.fluxcapacitor.javaclient.common.serialization.upcasting.UpcasterChain Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of java-client Show documentation
Show all versions of java-client Show documentation
Default Java client library for interfacing with Flux Capacitor.
/*
* Copyright (c) 2016-2017 Flux Capacitor.
*
* 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 io.fluxcapacitor.javaclient.common.serialization.upcasting;
import io.fluxcapacitor.common.api.Data;
import io.fluxcapacitor.common.api.SerializedObject;
import io.fluxcapacitor.javaclient.common.serialization.SerializationException;
import lombok.AllArgsConstructor;
import lombok.Value;
import lombok.experimental.Wither;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import static java.lang.String.format;
import static java.util.function.Function.identity;
import static java.util.stream.Collectors.toMap;
public class UpcasterChain {
public static Upcaster> create(Collection> upcasters, Converter converter) {
if (upcasters.isEmpty()) {
return s -> s;
}
Upcaster> upcasterChain = create(upcasters, converter.getDataType());
return stream -> {
Stream> converted = stream.map(s -> new ConvertingSerializedObject<>(s, converter));
Stream> upcasted = upcasterChain.upcast(converted);
return upcasted.map(ConvertingSerializedObject::getResult);
};
}
protected static > Upcaster create(Collection> upcasters, Class dataType) {
if (upcasters.isEmpty()) {
return s -> s;
}
List> upcasterList = UpcastInspector.inspect(upcasters, dataType);
UpcasterChain upcasterChain = new UpcasterChain<>(upcasterList);
return upcasterChain::upcast;
}
private final Map> upcasters;
protected UpcasterChain(Collection> upcasters) {
this.upcasters =
upcasters.stream().collect(toMap(u -> new DataRevision(u.getAnnotation()), identity(), (a, b) -> {
throw new SerializationException(
format("Failed to create upcaster chain. Methods '%s' and '%s' both apply to the same data revision.",
a, b));
}));
}
protected > Stream upcast(Stream input) {
return input.flatMap(i -> Optional.ofNullable(upcasters.get(new DataRevision(i.data())))
.map(upcaster -> upcast(upcaster.upcast(i)))
.orElse(Stream.of(i)));
}
@Value
@AllArgsConstructor
protected static class DataRevision {
String type;
int revision;
protected DataRevision(Data> data) {
this(data.getType(), data.getRevision());
}
protected DataRevision(Upcast annotation) {
this(annotation.type(), annotation.revision());
}
}
@AllArgsConstructor
protected static class ConvertingSerializedObject implements SerializedObject> {
private final SerializedObject source;
private final Converter converter;
@Wither
private Data data;
public ConvertingSerializedObject(SerializedObject source, Converter converter) {
this.source = source;
this.converter = converter;
this.data = converter.convert(source.data());
}
@Override
public Data data() {
return data;
}
public SerializedObject getResult() {
return source.withData(converter.convertBack(data));
}
}
}