Skip to content

Commit

Permalink
Removed BagTypeAdapter in favor of Container1TypeAdapter and Containe…
Browse files Browse the repository at this point in the history
…r2TypeAdapter
  • Loading branch information
lyubomyr-shaydariv committed Sep 25, 2024
1 parent a523460 commit 54a6400
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 85 deletions.
12 changes: 12 additions & 0 deletions src/main/java/lsh/ext/gson/ITypeAdapterFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ interface ITypeResolver<K> {

<T> TypeAdapter<T> getTypeAdapter(int index);

<T> TypeAdapter<T> getTypeAdapterForClass(Class<T> klass);

}

@SuppressWarnings("NewClassNamingConvention")
Expand Down Expand Up @@ -58,6 +60,11 @@ public <INNER_T> TypeAdapter<INNER_T> getTypeAdapter(final int index) {
final TypeToken<INNER_T> o = (TypeToken<INNER_T>) TypeToken.get(typeArgument);
return gson.getAdapter(o);
}

@Override
public <T> TypeAdapter<T> getTypeAdapterForClass(final Class<T> klass) {
return gson.getAdapter(klass);
}
};
@SuppressWarnings("unchecked")
final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) createTypeAdapter.apply(typeResolver);
Expand Down Expand Up @@ -97,6 +104,11 @@ public <INNER_T> TypeAdapter<INNER_T> getTypeAdapter(final int index) {
final TypeToken<INNER_T> o = (TypeToken<INNER_T>) TypeToken.get(typeArgument);
return gson.getAdapter(o);
}

@Override
public <T> TypeAdapter<T> getTypeAdapterForClass(final Class<T> klass) {
return gson.getAdapter(klass);
}
};
@SuppressWarnings("unchecked")
final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) createTypeAdapter.apply(typeResolver);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package lsh.ext.gson.ext.org.apache.commons.collections4;

import java.util.AbstractMap;
import java.util.Map;
import java.util.function.Function;
import java.util.function.Supplier;
Expand All @@ -12,18 +13,45 @@
import lsh.ext.gson.IBuilder2;
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.BidiMap;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.collections4.MultiSet;
import org.apache.commons.collections4.MultiValuedMap;

@UtilityClass
public final class ApacheCommonsCollections4TypeAdapter {

public static <E> TypeAdapter<Bag<E>> forBag(
final TypeAdapter<E> typeAdapter,
final Supplier<? extends IBuilder1<? super E, ? extends Bag<E>>> builderFactory
) {
return Container1TypeAdapter.getInstance(typeAdapter, Bag::iterator, builderFactory);
}

public static TypeAdapter<Bag<String>> forBagNCopies(
final TypeAdapter<Integer> integerTypeAdapter,
final Supplier<? extends IBuilder2<? super String, ? super Integer, ? extends Bag<String>>> builderFactory
) {
return forBagNCopies(integerTypeAdapter, builderFactory, Function.identity(), Function.identity());
}

public static <E> TypeAdapter<Bag<E>> forBagNCopies(
final TypeAdapter<Integer> integerTypeAdapter,
final Supplier<? extends IBuilder2<? super E, ? super Integer, ? extends Bag<E>>> builderFactory,
final Function<? super E, String> toName,
final Function<? super String, ? extends E> fromName
) {
return BagTypeAdapter.getInstance(builderFactory, toName, fromName);
return Container2TypeAdapter.<E, Integer, Bag<E>, Map.Entry<String, Integer>>getInstance(
integerTypeAdapter,
es -> IteratorUtils.transformedIterator(
es.uniqueSet().iterator(),
e -> new AbstractMap.SimpleImmutableEntry<>(toName.apply(e), es.getCount(e))
),
e -> fromName.apply(e.getKey()),
Map.Entry::getValue,
toName,
fromName,
builderFactory
);
}

public static <V> TypeAdapter<BidiMap<String, V>> forBidiMap(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.util.function.Supplier;

import com.google.common.collect.BiMap;
import com.google.gson.TypeAdapter;
import com.google.gson.reflect.TypeToken;
import lombok.experimental.UtilityClass;
import lsh.ext.gson.IBuilder1;
Expand Down Expand Up @@ -36,17 +37,28 @@ public static <E> ITypeAdapterFactory<Bag<E>> forBag(
final Function<? super E, String> toKey,
final Function<? super String, ? extends E> fromKey
) {
return ITypeAdapterFactory.forClassHierarchy(Bag.class, typeResolver -> ApacheCommonsCollections4TypeAdapter.forBag(lookup.lookup(typeResolver.getTypeToken()), toKey, fromKey));
return ITypeAdapterFactory.forClassHierarchy(
Bag.class,
typeResolver -> {
final TypeAdapter<Integer> integerTypeAdapter = typeResolver.getTypeAdapterForClass(int.class);
return ApacheCommonsCollections4TypeAdapter.forBagNCopies(
integerTypeAdapter,
lookup.lookup(typeResolver.getTypeToken()),
toKey,
fromKey
);
}
);
}

// TODO handle all known implementations
public static <E> Supplier<IBuilder2<E, Integer, Bag<E>>> defaultBuilderForBag(final TypeToken<? super Bag<E>> typeToken) {
@SuppressWarnings("unchecked")
final Class<? super Bag<?>> rawType = (Class<? super Bag<?>>) typeToken.getRawType();
if ( HashBag.class.isAssignableFrom(rawType) ) {
return () -> Builder.forBag(new HashBag<>());
return () -> Builder.forBagNCopies(HashBag::new);
}
return () -> Builder.forBag(new HashBag<>());
return () -> Builder.forBagNCopies(HashBag::new);
}

public static final ITypeAdapterFactory<BidiMap<String, Object>> defaultForBidiMap = forBidiMap(ApacheCommonsCollections4TypeAdapterFactory::defaultBuilderForBidiMap);
Expand Down Expand Up @@ -117,12 +129,12 @@ public static <V> Supplier<IBuilder2<String, V, MultiValuedMap<String, V>>> defa
@SuppressWarnings("unchecked")
final Class<? extends MultiValuedMap<?, ?>> rawType = (Class<? extends MultiValuedMap<?, ?>>) typeToken.getRawType();
if ( ArrayListValuedHashMap.class.isAssignableFrom(rawType) ) {
return () -> Builder.forMultiValuedMap(new ArrayListValuedHashMap<>());
return () -> Builder.forMultiValuedMap(ArrayListValuedHashMap::new);
}
if ( HashSetValuedHashMap.class.isAssignableFrom(rawType) ) {
return () -> Builder.forMultiValuedMap(new HashSetValuedHashMap<>());
return () -> Builder.forMultiValuedMap(HashSetValuedHashMap::new);
}
return () -> Builder.forMultiValuedMap(new ArrayListValuedHashMap<>());
return () -> Builder.forMultiValuedMap(ArrayListValuedHashMap::new);
}

}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,39 +1,26 @@
package lsh.ext.gson.ext.org.apache.commons.collections4;

import java.util.function.Supplier;

import lombok.experimental.UtilityClass;
import lsh.ext.gson.IBuilder1;
import lsh.ext.gson.IBuilder2;
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.MultiValuedMap;

@UtilityClass
public final class Builder {

public static <E, B extends Bag<E>> IBuilder2<E, Integer, B> forBag(final B bag) {
return new IBuilder2<>() {
@Override
public void accept(final E e, final Integer n) {
bag.add(e, n);
}

@Override
public B build() {
return bag;
}
};
public static <E, B extends Bag<E>> IBuilder1<E, B> forBag(final Supplier<? extends B> create) {
return IBuilder1.of(create, (e, bag) -> bag.add(e));
}

public static <K, V, M extends MultiValuedMap<K, V>> IBuilder2<K, V, M> forMultiValuedMap(final M multiValuedMap) {
return new IBuilder2<>() {
@Override
public void accept(final K k, final V v) {
multiValuedMap.put(k, v);
}
public static <E, B extends Bag<E>> IBuilder2<E, Integer, B> forBagNCopies(final Supplier<? extends B> create) {
return IBuilder2.of(create, (e, nCopies, bag) -> bag.add(e, nCopies));
}

@Override
public M build() {
return multiValuedMap;
}
};
public static <K, V, M extends MultiValuedMap<K, V>> IBuilder2<K, V, M> forMultiValuedMap(final Supplier<? extends M> create) {
return IBuilder2.of(create, (k, v, map) -> map.put(k, v));
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package lsh.ext.gson.ext.org.apache.commons.collections4;

import java.io.IOException;
import java.util.function.Function;

import com.google.gson.TypeAdapter;
import lsh.ext.gson.IBuilder2;
import lsh.ext.gson.test.TestTypeAdapters;
import org.apache.commons.collections4.Bag;
import org.apache.commons.collections4.bag.TreeBag;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public final class ApacheCommonsCollections4TypeAdapterTest {

@Test
public void testForBagRoundTrip()
throws IOException {
final TypeAdapter<Bag<String>> unit = ApacheCommonsCollections4TypeAdapter.forBag(
TestTypeAdapters.stringTypeAdapter,
() -> Builder.forBag(TreeBag::new)
);
final Bag<String> before = new TreeBag<>();
before.add("foo");
before.add("bar");
before.add("bar");
before.add("baz");
before.add("baz");
before.add("baz");
final String json = unit.toJson(before);
Assertions.assertEquals("[\"bar\",\"bar\",\"baz\",\"baz\",\"baz\",\"foo\"]", json);
final Bag<String> actual = unit.fromJson(json);
Assertions.assertIterableEquals(before, actual);
}

@Test
public void testForBagNCopiesForRoundTrip()
throws IOException {
@SuppressWarnings("RedundantTypeArguments")
final TypeAdapter<Bag<String>> unit = ApacheCommonsCollections4TypeAdapter.<String>forBagNCopies(
TestTypeAdapters.integerTypeAdapter,
() -> IBuilder2.of(TreeBag::new, (e, nCopies, strings) -> strings.add(e, nCopies), Function.identity())
);
final Bag<String> before = new TreeBag<>();
before.add("foo");
before.add("bar");
before.add("bar");
before.add("baz");
before.add("baz");
before.add("baz");
final String json = unit.toJson(before);
Assertions.assertEquals("{\"bar\":2,\"baz\":3,\"foo\":1}", json);
final Bag<String> actual = unit.fromJson(json);
Assertions.assertIterableEquals(before, actual);
}

}

0 comments on commit 54a6400

Please sign in to comment.