
io.fluxcapacitor.javaclient.common.serialization.casting.CasterChain 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) Flux Capacitor IP B.V. or its affiliates. All Rights Reserved.
*
* 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.casting;
import io.fluxcapacitor.common.api.Data;
import io.fluxcapacitor.common.api.SerializedObject;
import io.fluxcapacitor.javaclient.common.serialization.DeserializationException;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Value;
import lombok.With;
import java.util.Collection;
import java.util.Comparator;
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 CasterChain {
private static final Comparator> upcasterComparator =
Comparator., Integer>comparing(u -> u.getParameters().revision())
.thenComparing(u -> u.getParameters().type());
private static final Comparator> downcasterComparator =
Comparator., Integer>comparing(u -> u.getParameters().revision()).reversed()
.thenComparing(u -> u.getParameters().type());
public static Caster> createUpcaster(Collection> casterCandidates,
Converter converter) {
if (casterCandidates.isEmpty()) {
return (s, desiredRevision) -> s;
}
Caster> casterChain = create(casterCandidates, converter.getDataType(), false);
return (stream, desiredRevision) -> {
Stream> converted =
stream.map(s -> new ConvertingSerializedObject<>(s, converter));
Stream> casted = casterChain.cast(converted);
return casted.map(ConvertingSerializedObject::getResult);
};
}
public static > Caster create(Collection> casterCandidates,
Class dataType, boolean down) {
if (casterCandidates.isEmpty()) {
return (s, desiredRevision) -> s;
}
List> upcasterList =
CastInspector.getCasters(down ? Downcast.class : Upcast.class, casterCandidates, dataType,
down ? downcasterComparator : upcasterComparator);
CasterChain casterChain = new CasterChain<>(upcasterList, down);
return casterChain::cast;
}
private final Map> casters;
private final boolean down;
protected CasterChain(Collection> casters, boolean down) {
this.casters =
casters.stream().collect(toMap(u -> new DataRevision(u.getParameters()), identity(), (a, b) -> {
throw new DeserializationException(
format("Failed to create caster chain. Methods '%s' and '%s' both apply to the same data revision.",
a, b));
}));
this.down = down;
}
protected > Stream cast(Stream input, Integer desiredRevision) {
return doCast(input, desiredRevision);
}
protected > Stream doCast(Stream input, Integer desiredRevision) {
return input.flatMap(i -> {
boolean completed = desiredRevision != null
&& (down ? i.getRevision() <= desiredRevision : i.getRevision() >= desiredRevision);
return completed ? Stream.of(i)
: Optional.ofNullable(casters.get(new DataRevision(i.getType(), i.getRevision())))
.map(caster -> doCast(caster.cast(i), desiredRevision))
.orElseGet(() -> Stream.of(i));
});
}
@Value
@AllArgsConstructor
protected static class DataRevision {
String type;
int revision;
DataRevision(CastParameters annotation) {
this(annotation.type(), annotation.revision());
}
}
@AllArgsConstructor
protected static class ConvertingSerializedObject implements SerializedObject> {
@Getter
private final SerializedObject source;
private final Converter converter;
@With
private Data data;
public ConvertingSerializedObject(SerializedObject source, Converter converter) {
this.source = source;
this.converter = converter;
}
@Override
public Data data() {
if (data == null) {
data = converter.convert(source.data());
}
return data;
}
@Override
public String getType() {
return data == null ? source.getType() : data.getType();
}
@Override
public int getRevision() {
return data == null ? source.getRevision() : data.getRevision();
}
public SerializedObject getResult() {
return data == null ? source : source.withData(converter.convertBack(data));
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy