helpers for empty collections

This commit is contained in:
Adrian Cole 2012-09-15 23:43:50 -07:00
parent 0b31622267
commit 49877c8f06
12 changed files with 357 additions and 12 deletions

View File

@ -26,6 +26,7 @@ import org.jclouds.javax.annotation.Nullable;
import com.google.common.annotations.Beta;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSet;
/**
* Utilities for using {@link IterableWithMarker}s.
@ -34,6 +35,9 @@ import com.google.common.base.Optional;
*/
@Beta
public class IterableWithMarkers {
@SuppressWarnings("rawtypes")
public static final IterableWithMarker EMPTY = from(ImmutableSet.of());
/**
* Returns a paginated iterable containing the given elements and null marker.

View File

@ -35,6 +35,17 @@ import com.google.common.collect.ImmutableSet;
*/
@Beta
public class PagedIterables {
@SuppressWarnings("rawtypes")
public static final PagedIterable EMPTY = new PagedIterable() {
@Override
public Iterator<IterableWithMarker> iterator() {
return ImmutableSet.of(IterableWithMarkers.EMPTY).iterator();
}
};
/**
* @param only
* the only page of data

View File

@ -39,6 +39,8 @@ import org.jclouds.json.Json;
import org.jclouds.json.internal.DeserializationConstructorAndReflectiveTypeAdapterFactory;
import org.jclouds.json.internal.EnumTypeAdapterThatReturnsFromValue;
import org.jclouds.json.internal.GsonWrapper;
import org.jclouds.json.internal.IgnoreNullFluentIterableTypeAdapterFactory;
import org.jclouds.json.internal.IgnoreNullIterableTypeAdapterFactory;
import org.jclouds.json.internal.IgnoreNullMapTypeAdapterFactory;
import org.jclouds.json.internal.IgnoreNullMultimapTypeAdapterFactory;
import org.jclouds.json.internal.IgnoreNullSetTypeAdapterFactory;
@ -81,7 +83,10 @@ public class GsonModule extends AbstractModule {
@Provides
@Singleton
Gson provideGson(TypeAdapter<JsonBall> jsonAdapter, DateAdapter adapter, ByteListAdapter byteListAdapter,
ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings)
ByteArrayAdapter byteArrayAdapter, PropertiesAdapter propertiesAdapter, JsonAdapterBindings bindings,
OptionalTypeAdapterFactory optional, IgnoreNullSetTypeAdapterFactory set,
IgnoreNullMapTypeAdapterFactory map, IgnoreNullMultimapTypeAdapterFactory multimap,
IgnoreNullIterableTypeAdapterFactory iterable, IgnoreNullFluentIterableTypeAdapterFactory fluentIterable)
throws Exception {
FieldNamingStrategy serializationPolicy = new AnnotationOrNameFieldNamingStrategy(new ExtractSerializedName(),
@ -96,10 +101,12 @@ public class GsonModule extends AbstractModule {
}.getType(), byteListAdapter.nullSafe());
builder.registerTypeAdapter(byte[].class, byteArrayAdapter.nullSafe());
builder.registerTypeAdapter(JsonBall.class, jsonAdapter.nullSafe());
builder.registerTypeAdapterFactory(new OptionalTypeAdapterFactory());
builder.registerTypeAdapterFactory(new IgnoreNullSetTypeAdapterFactory());
builder.registerTypeAdapterFactory(new IgnoreNullMapTypeAdapterFactory());
builder.registerTypeAdapterFactory(new IgnoreNullMultimapTypeAdapterFactory());
builder.registerTypeAdapterFactory(optional);
builder.registerTypeAdapterFactory(set);
builder.registerTypeAdapterFactory(map);
builder.registerTypeAdapterFactory(multimap);
builder.registerTypeAdapterFactory(iterable);
builder.registerTypeAdapterFactory(fluentIterable);
AnnotationConstructorNamingStrategy deserializationPolicy =
new AnnotationConstructorNamingStrategy(

View File

@ -0,0 +1,78 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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 org.jclouds.json.internal;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
/**
* Eliminates null values when deserializing FluentIterables
* <p/>
* Treats [null] as the empty set; [A, null] as [A]; etc.
*
* @author Adam Lowe
*/
public class IgnoreNullFluentIterableTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
if (typeToken.getRawType() != FluentIterable.class || !(type instanceof ParameterizedType)) {
return null;
}
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
return (TypeAdapter<T>) newFluentIterableAdapter(elementAdapter);
}
private <E> TypeAdapter<FluentIterable<E>> newFluentIterableAdapter(final TypeAdapter<E> elementAdapter) {
return new TypeAdapter<FluentIterable<E>>() {
public void write(JsonWriter out, FluentIterable<E> value) throws IOException {
out.beginArray();
for (E element : value) {
elementAdapter.write(out, element);
}
out.endArray();
}
public FluentIterable<E> read(JsonReader in) throws IOException {
in.beginArray();
Builder<E> builder = ImmutableList.<E>builder();
while (in.hasNext()) {
E element = elementAdapter.read(in);
if (element != null) builder.add(element);
}
in.endArray();
return FluentIterable.from(builder.build());
}
}.nullSafe();
}
}

View File

@ -0,0 +1,77 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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 org.jclouds.json.internal;
import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.gson.Gson;
import com.google.gson.TypeAdapter;
import com.google.gson.TypeAdapterFactory;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
/**
* Eliminates null values when deserializing Iterables
* <p/>
* Treats [null] as the empty set; [A, null] as [A]; etc.
*
* @author Adam Lowe
*/
public class IgnoreNullIterableTypeAdapterFactory implements TypeAdapterFactory {
@SuppressWarnings("unchecked")
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
if (typeToken.getRawType() != Iterable.class || !(type instanceof ParameterizedType)) {
return null;
}
Type elementType = ((ParameterizedType) type).getActualTypeArguments()[0];
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
return (TypeAdapter<T>) newIterableAdapter(elementAdapter);
}
private <E> TypeAdapter<Iterable<E>> newIterableAdapter(final TypeAdapter<E> elementAdapter) {
return new TypeAdapter<Iterable<E>>() {
public void write(JsonWriter out, Iterable<E> value) throws IOException {
out.beginArray();
for (E element : value) {
elementAdapter.write(out, element);
}
out.endArray();
}
public Iterable<E> read(JsonReader in) throws IOException {
in.beginArray();
Builder<E> builder = ImmutableList.<E>builder();
while (in.hasNext()) {
E element = elementAdapter.read(in);
if (element != null) builder.add(element);
}
in.endArray();
return builder.build();
}
}.nullSafe();
}
}

View File

@ -0,0 +1,59 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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 org.jclouds.rest.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.http.functions.ReturnTrueOn404;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ReturnEmptyFluentIterableOnNotFoundOr404 implements Function<Exception, Object> {
private final ReturnTrueOn404 rto404;
@Inject
private ReturnEmptyFluentIterableOnNotFoundOr404(ReturnTrueOn404 rto404) {
this.rto404 = checkNotNull(rto404, "rto404");
}
public Object apply(Exception from) {
Iterable<ResourceNotFoundException> throwables = Iterables.filter(Throwables.getCausalChain(from),
ResourceNotFoundException.class);
if (Iterables.size(throwables) >= 1) {
return FluentIterable.from(ImmutableSet.of());
} else if (rto404.apply(from)) {
return FluentIterable.from(ImmutableSet.of());
}
throw Throwables.propagate(from);
}
}

View File

@ -0,0 +1,58 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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 org.jclouds.rest.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.collect.IterableWithMarkers;
import org.jclouds.http.functions.ReturnTrueOn404;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ReturnEmptyIterableWithMarkerOnNotFoundOr404 implements Function<Exception, Object> {
private final ReturnTrueOn404 rto404;
@Inject
private ReturnEmptyIterableWithMarkerOnNotFoundOr404(ReturnTrueOn404 rto404) {
this.rto404 = checkNotNull(rto404, "rto404");
}
public Object apply(Exception from) {
Iterable<ResourceNotFoundException> throwables = Iterables.filter(Throwables.getCausalChain(from),
ResourceNotFoundException.class);
if (Iterables.size(throwables) >= 1) {
return IterableWithMarkers.EMPTY;
} else if (rto404.apply(from)) {
return IterableWithMarkers.EMPTY;
}
throw Throwables.propagate(from);
}
}

View File

@ -20,8 +20,6 @@ package org.jclouds.rest.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.List;
import javax.inject.Inject;
import javax.inject.Singleton;

View File

@ -20,8 +20,6 @@ package org.jclouds.rest.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Map;
import javax.inject.Inject;
import javax.inject.Singleton;

View File

@ -30,7 +30,6 @@ import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
/**
*

View File

@ -0,0 +1,58 @@
/**
* Licensed to jclouds, Inc. (jclouds) under one or more
* contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. jclouds licenses this file
* to you 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 org.jclouds.rest.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.inject.Inject;
import javax.inject.Singleton;
import org.jclouds.collect.PagedIterables;
import org.jclouds.http.functions.ReturnTrueOn404;
import org.jclouds.rest.ResourceNotFoundException;
import com.google.common.base.Function;
import com.google.common.base.Throwables;
import com.google.common.collect.Iterables;
/**
*
* @author Adrian Cole
*/
@Singleton
public class ReturnEmptyPagedIterableOnNotFoundOr404 implements Function<Exception, Object> {
private final ReturnTrueOn404 rto404;
@Inject
private ReturnEmptyPagedIterableOnNotFoundOr404(ReturnTrueOn404 rto404) {
this.rto404 = checkNotNull(rto404, "rto404");
}
public Object apply(Exception from) {
Iterable<ResourceNotFoundException> throwables = Iterables.filter(Throwables.getCausalChain(from),
ResourceNotFoundException.class);
if (Iterables.size(throwables) >= 1) {
return PagedIterables.EMPTY;
} else if (rto404.apply(from)) {
return PagedIterables.EMPTY;
}
throw Throwables.propagate(from);
}
}

View File

@ -20,8 +20,6 @@ package org.jclouds.rest.functions;
import static com.google.common.base.Preconditions.checkNotNull;
import java.util.Set;
import javax.inject.Inject;
import javax.inject.Singleton;