• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.base;
18 
19 import static com.google.common.base.Preconditions.checkNotNull;
20 
21 import com.google.common.annotations.Beta;
22 import com.google.common.annotations.GwtCompatible;
23 
24 import java.io.Serializable;
25 import java.util.Iterator;
26 
27 import javax.annotation.Nullable;
28 
29 /**
30  * A function from {@code A} to {@code B} with an associated <i>reverse</i> function from {@code B}
31  * to {@code A}; used for converting back and forth between <i>different representations of the same
32  * information</i>.
33  *
34  * <h3>Invertibility</h3>
35  *
36  * <p>The reverse operation <b>may</b> be a strict <i>inverse</i> (meaning that {@code
37  * converter.reverse().convert(converter.convert(a)).equals(a)} is always true). However, it is
38  * very common (perhaps <i>more</i> common) for round-trip conversion to be <i>lossy</i>. Consider
39  * an example round-trip using {@link com.google.common.primitives.Doubles#stringConverter}:
40  *
41  * <ol>
42  * <li>{@code stringConverter().convert("1.00")} returns the {@code Double} value {@code 1.0}
43  * <li>{@code stringConverter().reverse().convert(1.0)} returns the string {@code "1.0"} --
44  *     <i>not</i> the same string ({@code "1.00"}) we started with
45  * </ol>
46  *
47  * <p>Note that it should still be the case that the round-tripped and original objects are
48  * <i>similar</i>.
49  *
50  * <h3>Nullability</h3>
51  *
52  * <p>A converter always converts {@code null} to {@code null} and non-null references to non-null
53  * references. It would not make sense to consider {@code null} and a non-null reference to be
54  * "different representations of the same information", since one is distinguishable from
55  * <i>missing</i> information and the other is not. The {@link #convert} method handles this null
56  * behavior for all converters; implementations of {@link #doForward} and {@link #doBackward} are
57  * guaranteed to never be passed {@code null}, and must never return {@code null}.
58  *
59 
60  * <h3>Common ways to use</h3>
61  *
62  * <p>Getting a converter:
63  *
64  * <ul>
65  * <li>Use a provided converter implementation, such as {@link Enums#stringConverter}, {@link
66  *     com.google.common.primitives.Ints#stringConverter Ints.stringConverter} or the {@linkplain
67  *     #reverse reverse} views of these.
68  * <li>Convert between specific preset values using {@link
69  *     com.google.common.collect.Maps#asConverter Maps.asConverter}. For example, use this to create
70  *     a "fake" converter for a unit test. It is unnecessary (and confusing) to <i>mock</i> the
71  *     {@code Converter} type using a mocking framework.
72  * <li>Otherwise, extend this class and implement its {@link #doForward} and {@link #doBackward}
73  *     methods.
74  * </ul>
75  *
76  * <p>Using a converter:
77  *
78  * <ul>
79  * <li>Convert one instance in the "forward" direction using {@code converter.convert(a)}.
80  * <li>Convert multiple instances "forward" using {@code converter.convertAll(as)}.
81  * <li>Convert in the "backward" direction using {@code converter.reverse().convert(b)} or {@code
82  *     converter.reverse().convertAll(bs)}.
83  * <li>Use {@code converter} or {@code converter.reverse()} anywhere a {@link Function} is accepted
84  * <li><b>Do not</b> call {@link #doForward} or {@link #doBackward} directly; these exist only to be
85  *     overridden.
86  * </ul>
87  *
88  * @author Mike Ward
89  * @author Kurt Alfred Kluever
90  * @author Gregory Kick
91  * @since 16.0
92  */
93 @Beta
94 @GwtCompatible
95 public abstract class Converter<A, B> implements Function<A, B> {
96   private final boolean handleNullAutomatically;
97 
98   // We lazily cache the reverse view to avoid allocating on every call to reverse().
99   private transient Converter<B, A> reverse;
100 
101   /** Constructor for use by subclasses. */
Converter()102   protected Converter() {
103     this(true);
104   }
105 
106   /**
107    * Constructor used only by {@code LegacyConverter} to suspend automatic null-handling.
108    */
Converter(boolean handleNullAutomatically)109   Converter(boolean handleNullAutomatically) {
110     this.handleNullAutomatically = handleNullAutomatically;
111   }
112 
113   // SPI methods (what subclasses must implement)
114 
115   /**
116    * Returns a representation of {@code a} as an instance of type {@code B}. If {@code a} cannot be
117    * converted, an unchecked exception (such as {@link IllegalArgumentException}) should be thrown.
118    *
119    * @param a the instance to convert; will never be null
120    * @return the converted instance; <b>must not</b> be null
121    */
doForward(A a)122   protected abstract B doForward(A a);
123 
124   /**
125    * Returns a representation of {@code b} as an instance of type {@code A}. If {@code b} cannot be
126    * converted, an unchecked exception (such as {@link IllegalArgumentException}) should be thrown.
127    *
128    * @param b the instance to convert; will never be null
129    * @return the converted instance; <b>must not</b> be null
130    * @throws UnsupportedOperationException if backward conversion is not implemented; this should be
131    *     very rare. Note that if backward conversion is not only unimplemented but
132    *     unimplement<i>able</i> (for example, consider a {@code Converter<Chicken, ChickenNugget>}),
133    *     then this is not logically a {@code Converter} at all, and should just implement {@link
134    *     Function}.
135    */
doBackward(B b)136   protected abstract A doBackward(B b);
137 
138   // API (consumer-side) methods
139 
140   /**
141    * Returns a representation of {@code a} as an instance of type {@code B}.
142    *
143    * @return the converted value; is null <i>if and only if</i> {@code a} is null
144    */
145   @Nullable
convert(@ullable A a)146   public final B convert(@Nullable A a) {
147     return correctedDoForward(a);
148   }
149 
150   @Nullable
correctedDoForward(@ullable A a)151   B correctedDoForward(@Nullable A a) {
152     if (handleNullAutomatically) {
153       // TODO(kevinb): we shouldn't be checking for a null result at runtime. Assert?
154       return a == null ? null : checkNotNull(doForward(a));
155     } else {
156       return doForward(a);
157     }
158   }
159 
160   @Nullable
correctedDoBackward(@ullable B b)161   A correctedDoBackward(@Nullable B b) {
162     if (handleNullAutomatically) {
163       // TODO(kevinb): we shouldn't be checking for a null result at runtime. Assert?
164       return b == null ? null : checkNotNull(doBackward(b));
165     } else {
166       return doBackward(b);
167     }
168   }
169 
170   /**
171    * Returns an iterable that applies {@code convert} to each element of {@code fromIterable}. The
172    * conversion is done lazily.
173    *
174    * <p>The returned iterable's iterator supports {@code remove()} if the input iterator does. After
175    * a successful {@code remove()} call, {@code fromIterable} no longer contains the corresponding
176    * element.
177    */
convertAll(final Iterable<? extends A> fromIterable)178   public Iterable<B> convertAll(final Iterable<? extends A> fromIterable) {
179     checkNotNull(fromIterable, "fromIterable");
180     return new Iterable<B>() {
181       @Override public Iterator<B> iterator() {
182         return new Iterator<B>() {
183           private final Iterator<? extends A> fromIterator = fromIterable.iterator();
184 
185           @Override
186           public boolean hasNext() {
187             return fromIterator.hasNext();
188           }
189 
190           @Override
191           public B next() {
192             return convert(fromIterator.next());
193           }
194 
195           @Override
196           public void remove() {
197             fromIterator.remove();
198           }
199         };
200       }
201     };
202   }
203 
204   /**
205    * Returns the reversed view of this converter, which converts {@code this.convert(a)} back to a
206    * value roughly equivalent to {@code a}.
207    *
208    * <p>The returned converter is serializable if {@code this} converter is.
209    */
210   // TODO(user): Make this method final
211   public Converter<B, A> reverse() {
212     Converter<B, A> result = reverse;
213     return (result == null) ? reverse = new ReverseConverter<A, B>(this) : result;
214   }
215 
216   private static final class ReverseConverter<A, B>
217       extends Converter<B, A> implements Serializable {
218     final Converter<A, B> original;
219 
220     ReverseConverter(Converter<A, B> original) {
221       this.original = original;
222     }
223 
224     /*
225      * These gymnastics are a little confusing. Basically this class has neither legacy nor
226      * non-legacy behavior; it just needs to let the behavior of the backing converter shine
227      * through. So, we override the correctedDo* methods, after which the do* methods should never
228      * be reached.
229      */
230 
231     @Override
232     protected A doForward(B b) {
233       throw new AssertionError();
234     }
235 
236     @Override
237     protected B doBackward(A a) {
238       throw new AssertionError();
239     }
240 
241     @Override
242     @Nullable
243     A correctedDoForward(@Nullable B b) {
244       return original.correctedDoBackward(b);
245     }
246 
247     @Override
248     @Nullable
249     B correctedDoBackward(@Nullable A a) {
250       return original.correctedDoForward(a);
251     }
252 
253     @Override
254     public Converter<A, B> reverse() {
255       return original;
256     }
257 
258     @Override
259     public boolean equals(@Nullable Object object) {
260       if (object instanceof ReverseConverter) {
261         ReverseConverter<?, ?> that = (ReverseConverter<?, ?>) object;
262         return this.original.equals(that.original);
263       }
264       return false;
265     }
266 
267     @Override
268     public int hashCode() {
269       return ~original.hashCode();
270     }
271 
272     @Override
273     public String toString() {
274       return original + ".reverse()";
275     }
276 
277     private static final long serialVersionUID = 0L;
278   }
279 
280   /**
281    * Returns a converter whose {@code convert} method applies {@code secondConverter} to the result
282    * of this converter. Its {@code reverse} method applies the converters in reverse order.
283    *
284    * <p>The returned converter is serializable if {@code this} converter and {@code secondConverter}
285    * are.
286    */
287   public final <C> Converter<A, C> andThen(Converter<B, C> secondConverter) {
288     return doAndThen(secondConverter);
289   }
290 
291   /**
292    * Package-private non-final implementation of andThen() so only we can override it.
293    */
294   <C> Converter<A, C> doAndThen(Converter<B, C> secondConverter) {
295     return new ConverterComposition<A, B, C>(this, checkNotNull(secondConverter));
296   }
297 
298   private static final class ConverterComposition<A, B, C>
299       extends Converter<A, C> implements Serializable {
300     final Converter<A, B> first;
301     final Converter<B, C> second;
302 
303     ConverterComposition(Converter<A, B> first, Converter<B, C> second) {
304       this.first = first;
305       this.second = second;
306     }
307 
308     /*
309      * These gymnastics are a little confusing. Basically this class has neither legacy nor
310      * non-legacy behavior; it just needs to let the behaviors of the backing converters shine
311      * through (which might even differ from each other!). So, we override the correctedDo* methods,
312      * after which the do* methods should never be reached.
313      */
314 
315     @Override
316     protected C doForward(A a) {
317       throw new AssertionError();
318     }
319 
320     @Override
321     protected A doBackward(C c) {
322       throw new AssertionError();
323     }
324 
325     @Override
326     @Nullable
327     C correctedDoForward(@Nullable A a) {
328       return second.correctedDoForward(first.correctedDoForward(a));
329     }
330 
331     @Override
332     @Nullable
333     A correctedDoBackward(@Nullable C c) {
334       return first.correctedDoBackward(second.correctedDoBackward(c));
335     }
336 
337     @Override
338     public boolean equals(@Nullable Object object) {
339       if (object instanceof ConverterComposition) {
340         ConverterComposition<?, ?, ?> that = (ConverterComposition<?, ?, ?>) object;
341         return this.first.equals(that.first)
342             && this.second.equals(that.second);
343       }
344       return false;
345     }
346 
347     @Override
348     public int hashCode() {
349       return 31 * first.hashCode() + second.hashCode();
350     }
351 
352     @Override
353     public String toString() {
354       return first + ".andThen(" + second + ")";
355     }
356 
357     private static final long serialVersionUID = 0L;
358   }
359 
360   /**
361    * @deprecated Provided to satisfy the {@code Function} interface; use {@link #convert} instead.
362    */
363   @Deprecated
364   @Override
365   @Nullable
366   public final B apply(@Nullable A a) {
367     return convert(a);
368   }
369 
370   /**
371    * Indicates whether another object is equal to this converter.
372    *
373    * <p>Most implementations will have no reason to override the behavior of {@link Object#equals}.
374    * However, an implementation may also choose to return {@code true} whenever {@code object} is a
375    * {@link Converter} that it considers <i>interchangeable</i> with this one. "Interchangeable"
376    * <i>typically</i> means that {@code Objects.equal(this.convert(a), that.convert(a))} is true for
377    * all {@code a} of type {@code A} (and similarly for {@code reverse}). Note that a {@code false}
378    * result from this method does not imply that the converters are known <i>not</i> to be
379    * interchangeable.
380    */
381   @Override
382   public boolean equals(@Nullable Object object) {
383     return super.equals(object);
384   }
385 
386   // Static converters
387 
388   /**
389    * Returns a converter based on <i>existing</i> forward and backward functions. Note that it is
390    * unnecessary to create <i>new</i> classes implementing {@code Function} just to pass them in
391    * here. Instead, simply subclass {@code Converter} and implement its {@link #doForward} and
392    * {@link #doBackward} methods directly.
393    *
394    * <p>These functions will never be passed {@code null} and must not under any circumstances
395    * return {@code null}. If a value cannot be converted, the function should throw an unchecked
396    * exception (typically, but not necessarily, {@link IllegalArgumentException}).
397    *
398    * <p>The returned converter is serializable if both provided functions are.
399    *
400    * @since 17.0
401    */
402   public static <A, B> Converter<A, B> from(
403       Function<? super A, ? extends B> forwardFunction,
404       Function<? super B, ? extends A> backwardFunction) {
405     return new FunctionBasedConverter<A, B>(forwardFunction, backwardFunction);
406   }
407 
408   private static final class FunctionBasedConverter<A, B>
409       extends Converter<A, B> implements Serializable {
410     private final Function<? super A, ? extends B> forwardFunction;
411     private final Function<? super B, ? extends A> backwardFunction;
412 
413     private FunctionBasedConverter(
414         Function<? super A, ? extends B> forwardFunction,
415         Function<? super B, ? extends A> backwardFunction) {
416       this.forwardFunction = checkNotNull(forwardFunction);
417       this.backwardFunction = checkNotNull(backwardFunction);
418     }
419 
420     @Override
421     protected B doForward(A a) {
422       return forwardFunction.apply(a);
423     }
424 
425     @Override
426     protected A doBackward(B b) {
427       return backwardFunction.apply(b);
428     }
429 
430     @Override
431     public boolean equals(@Nullable Object object) {
432       if (object instanceof FunctionBasedConverter) {
433         FunctionBasedConverter<?, ?> that = (FunctionBasedConverter<?, ?>) object;
434         return this.forwardFunction.equals(that.forwardFunction)
435             && this.backwardFunction.equals(that.backwardFunction);
436       }
437       return false;
438     }
439 
440     @Override
441     public int hashCode() {
442       return forwardFunction.hashCode() * 31 + backwardFunction.hashCode();
443     }
444 
445     @Override
446     public String toString() {
447       return "Converter.from(" + forwardFunction + ", " + backwardFunction + ")";
448     }
449   }
450 
451   /**
452    * Returns a serializable converter that always converts or reverses an object to itself.
453    */
454   @SuppressWarnings("unchecked") // implementation is "fully variant"
455   public static <T> Converter<T, T> identity() {
456     return (IdentityConverter<T>) IdentityConverter.INSTANCE;
457   }
458 
459   /**
460    * A converter that always converts or reverses an object to itself. Note that T is now a
461    * "pass-through type".
462    */
463   private static final class IdentityConverter<T> extends Converter<T, T> implements Serializable {
464     static final IdentityConverter INSTANCE = new IdentityConverter();
465 
466     @Override
467     protected T doForward(T t) {
468       return t;
469     }
470 
471     @Override
472     protected T doBackward(T t) {
473       return t;
474     }
475 
476     @Override
477     public IdentityConverter<T> reverse() {
478       return this;
479     }
480 
481     @Override
482     <S> Converter<T, S> doAndThen(Converter<T, S> otherConverter) {
483       return checkNotNull(otherConverter, "otherConverter");
484     }
485 
486     /*
487      * We *could* override convertAll() to return its input, but it's a rather pointless
488      * optimization and opened up a weird type-safety problem.
489      */
490 
491     @Override
492     public String toString() {
493       return "Converter.identity()";
494     }
495 
496     private Object readResolve() {
497       return INSTANCE;
498     }
499 
500     private static final long serialVersionUID = 0L;
501   }
502 }
503