in sdk/src/main/java/com/google/cloud/dataflow/sdk/coders/Coder.java [98:269]
public void encode(T value, OutputStream outStream, Context context)
throws CoderException, IOException;
/**
* Decodes a value of type {@code T} from the given input stream in
* the given context. Returns the decoded value.
*
* @throws IOException if reading from the {@code InputStream} fails
* for some reason
* @throws CoderException if the value could not be decoded for some reason
*/
public T decode(InputStream inStream, Context context)
throws CoderException, IOException;
/**
* If this is a {@code Coder} for a parameterized type, returns the
* list of {@code Coder}s being used for each of the parameters, or
* returns {@code null} if this cannot be done or this is not a
* parameterized type.
*/
public List<? extends Coder<?>> getCoderArguments();
/**
* Returns the {@link CloudObject} that represents this {@code Coder}.
*/
public CloudObject asCloudObject();
/**
* Throw {@link NonDeterministicException} if the coding is not deterministic.
*
* <p>In order for a {@code Coder} to be considered deterministic,
* the following must be true:
* <ul>
* <li>two values that compare as equal (via {@code Object.equals()}
* or {@code Comparable.compareTo()}, if supported) have the same
* encoding.
* <li>the {@code Coder} always produces a canonical encoding, which is the
* same for an instance of an object even if produced on different
* computers at different times.
* </ul>
*
* @throws Coder.NonDeterministicException if this coder is not deterministic.
*/
public void verifyDeterministic() throws Coder.NonDeterministicException;
/**
* Returns true if whenever the encoded bytes of two values are equal, then the original values
* are equal according to {@code Objects.equals()} (note that this is well-defined for
* {@code null}). In other words, encoding is injective.
*
* <p>This condition is most notably false for arrays. More generally, this condition is false
* whenever {@code equals()} compares object identity, rather than performing a
* semantic/structural comparison.
*/
public boolean consistentWithEquals();
/**
* Returns an object with an {@code Object.equals()} method that represents structural equality
* on the argument.
*
* <p>For any two values {@code x} and {@code y} of type {@code T}, if their encoded bytes are the
* same, then it must be the case that {@code structuralValue(x).equals(@code structuralValue(y)}.
*
* <p>Most notably:
* <ul>
* <li>The structural value for an array coder should perform a structural comparison of the
* contents of the arrays, rather than the default behavior of comparing according to object
* identity.
* <li>The structural value for a coder accepting {@code null} should be a proper object with
* an {@code equals()} method, even if the input value is {@code null}.
* </ul>
*
* <p>See also {@link #consistentWithEquals()}.
*/
public Object structuralValue(T value) throws Exception;
/**
* Returns whether {@link #registerByteSizeObserver} cheap enough to
* call for every element, that is, if this {@code Coder} can
* calculate the byte size of the element to be coded in roughly
* constant time (or lazily).
*
* <p>Not intended to be called by user code, but instead by
* {@link com.google.cloud.dataflow.sdk.runners.PipelineRunner}
* implementations.
*/
public boolean isRegisterByteSizeObserverCheap(T value, Context context);
/**
* Notifies the {@code ElementByteSizeObserver} about the byte size
* of the encoded value using this {@code Coder}.
*
* <p>Not intended to be called by user code, but instead by
* {@link com.google.cloud.dataflow.sdk.runners.PipelineRunner}
* implementations.
*/
public void registerByteSizeObserver(
T value, ElementByteSizeObserver observer, Context context)
throws Exception;
/**
* An identifier for the binary format written by {@link #encode}.
*
* <p>This value, along with the fully qualified class name, forms an identifier for the
* binary format of this coder. Whenever this value changes, the new encoding is considered
* incompatible with the prior format: It is presumed that the prior version of the coder will
* be unable to correctly read the new format and the new version of the coder will be unable to
* correctly read the old format.
*
* <p>If the format is changed in a backwards-compatible way (the Coder can still accept data from
* the prior format), such as by adding optional fields to a Protocol Buffer or Avro definition,
* and you want Dataflow to understand that the new coder is compatible with the prior coder,
* this value must remain unchanged. It is then the responsibility of {@link #decode} to correctly
* read data from the prior format.
*/
@Experimental(Kind.CODER_ENCODING_ID)
public String getEncodingId();
/**
* A collection of encodings supported by {@link #decode} in addition to the encoding
* from {@link #getEncodingId()} (which is assumed supported).
*
* <p><i>This information is not currently used for any purpose</i>. It is descriptive only,
* and this method is subject to change.
*
* @see #getEncodingId()
*/
@Experimental(Kind.CODER_ENCODING_ID)
public Collection<String> getAllowedEncodings();
/**
* Exception thrown by {@link Coder#verifyDeterministic()} if the encoding is
* not deterministic.
*/
public static class NonDeterministicException extends Throwable {
private Coder<?> coder;
private List<String> reasons;
public NonDeterministicException(
Coder<?> coder, String reason, @Nullable NonDeterministicException e) {
this(coder, Arrays.asList(reason), e);
}
public NonDeterministicException(Coder<?> coder, String reason) {
this(coder, Arrays.asList(reason), null);
}
public NonDeterministicException(Coder<?> coder, List<String> reasons) {
this(coder, reasons, null);
}
public NonDeterministicException(
Coder<?> coder,
List<String> reasons,
@Nullable NonDeterministicException cause) {
super(cause);
Preconditions.checkArgument(reasons.size() > 0,
"Reasons must not be empty.");
this.reasons = reasons;
this.coder = coder;
}
public Iterable<String> getReasons() {
return reasons;
}
@Override
public String getMessage() {
return String.format("%s is not deterministic because:\n %s",
coder, Joiner.on("\n ").join(reasons));
}
}