Add BigIntegerCoder and tests
Project: http://git-wip-us.apache.org/repos/asf/incubator-beam/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-beam/commit/8268f1d7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-beam/tree/8268f1d7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-beam/diff/8268f1d7 Branch: refs/heads/python-sdk Commit: 8268f1d7ffdd1205a1904037f7dd1e1887a52f8d Parents: 6460df1 Author: Kenneth Knowles <[email protected]> Authored: Thu Jun 9 13:24:49 2016 -0700 Committer: Davor Bonaci <[email protected]> Committed: Mon Jun 20 15:14:30 2016 -0700 ---------------------------------------------------------------------- .../apache/beam/sdk/coders/BigIntegerCoder.java | 91 ++++++++++++++ .../beam/sdk/coders/BigIntegerCoderTest.java | 119 +++++++++++++++++++ 2 files changed, 210 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-beam/blob/8268f1d7/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/BigIntegerCoder.java ---------------------------------------------------------------------- diff --git a/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/BigIntegerCoder.java b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/BigIntegerCoder.java new file mode 100644 index 0000000..a41defe --- /dev/null +++ b/sdks/java/core/src/main/java/org/apache/beam/sdk/coders/BigIntegerCoder.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.beam.sdk.coders; + +import static com.google.common.base.Preconditions.checkNotNull; + +import com.fasterxml.jackson.annotation.JsonCreator; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; + +/** + * A {@link BigIntegerCoder} encodes a {@link BigInteger} as a byte array containing the big endian + * two's-complement representation, encoded via {@link ByteArrayCoder}. + */ +public class BigIntegerCoder extends AtomicCoder<BigInteger> { + + @JsonCreator + public static BigIntegerCoder of() { + return INSTANCE; + } + + ///////////////////////////////////////////////////////////////////////////// + + private static final BigIntegerCoder INSTANCE = new BigIntegerCoder(); + + private BigIntegerCoder() {} + + private final ByteArrayCoder byteArrayCoder = ByteArrayCoder.of(); + + @Override + public void encode(BigInteger value, OutputStream outStream, Context context) + throws IOException, CoderException { + checkNotNull(value, String.format("cannot encode a null %s", BigInteger.class.getSimpleName())); + byteArrayCoder.encode(value.toByteArray(), outStream, context); + } + + @Override + public BigInteger decode(InputStream inStream, Context context) + throws IOException, CoderException { + return new BigInteger(byteArrayCoder.decode(inStream, context)); + } + + /** + * {@inheritDoc} + * + * @return {@code true}. This coder is injective. + */ + @Override + public boolean consistentWithEquals() { + return true; + } + + /** + * {@inheritDoc} + * + * @return {@code true}, because {@link #getEncodedElementByteSize} runs in constant time. + */ + @Override + public boolean isRegisterByteSizeObserverCheap(BigInteger value, Context context) { + return true; + } + + /** + * {@inheritDoc} + * + * @return the size of the encoding as a byte array according to {@link ByteArrayCoder} + */ + @Override + protected long getEncodedElementByteSize(BigInteger value, Context context) throws Exception { + checkNotNull(value, String.format("cannot encode a null %s", BigInteger.class.getSimpleName())); + return byteArrayCoder.getEncodedElementByteSize(value.toByteArray(), context); + } +} http://git-wip-us.apache.org/repos/asf/incubator-beam/blob/8268f1d7/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/BigIntegerCoderTest.java ---------------------------------------------------------------------- diff --git a/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/BigIntegerCoderTest.java b/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/BigIntegerCoderTest.java new file mode 100644 index 0000000..3934b03 --- /dev/null +++ b/sdks/java/core/src/test/java/org/apache/beam/sdk/coders/BigIntegerCoderTest.java @@ -0,0 +1,119 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF 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.apache.beam.sdk.coders; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +import org.apache.beam.sdk.testing.CoderProperties; +import org.apache.beam.sdk.util.CoderUtils; +import org.apache.beam.sdk.util.common.Counter; +import org.apache.beam.sdk.util.common.Counter.AggregationKind; +import org.apache.beam.sdk.util.common.CounterName; +import org.apache.beam.sdk.util.common.ElementByteSizeObserver; + +import com.google.common.collect.ImmutableList; + +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.math.BigInteger; +import java.util.List; + +/** + * Test case for {@link BigIntegerCoder}. + */ +@RunWith(JUnit4.class) +public class BigIntegerCoderTest { + + @Rule public ExpectedException thrown = ExpectedException.none(); + + private static final Coder<BigInteger> TEST_CODER = BigIntegerCoder.of(); + + private static final List<BigInteger> TEST_VALUES = + ImmutableList.of( + BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.valueOf(Integer.MAX_VALUE)), + BigInteger.valueOf(Integer.MIN_VALUE).subtract(BigInteger.ONE), + BigInteger.valueOf(-1), + BigInteger.ZERO, + BigInteger.valueOf(1), + BigInteger.valueOf(Integer.MAX_VALUE).add(BigInteger.ONE), + BigInteger.valueOf(Integer.MAX_VALUE).multiply(BigInteger.TEN)); + + @Test + public void testDecodeEncodeEqual() throws Exception { + for (BigInteger value : TEST_VALUES) { + CoderProperties.coderDecodeEncodeEqual(TEST_CODER, value); + } + } + + // This should never change. The definition of big endian encoding is fixed. + private static final String EXPECTED_ENCODING_ID = ""; + + @Test + public void testEncodingId() throws Exception { + CoderProperties.coderHasEncodingId(TEST_CODER, EXPECTED_ENCODING_ID); + } + + /** + * Generated data to check that the wire format has not changed. To regenerate, see + * {@link org.apache.beam.sdk.coders.PrintBase64Encodings}. + */ + private static final List<String> TEST_ENCODINGS = + ImmutableList.of("_wAAAAE", "_3____8", "_w", "AA", "AQ", "AIAAAAA", "BP____Y"); + + @Test + public void testWireFormatEncode() throws Exception { + CoderProperties.coderEncodesBase64(TEST_CODER, TEST_VALUES, TEST_ENCODINGS); + } + + @Test + public void testGetEncodedElementByteSize() throws Exception { + Counter<Long> counter = Counter.longs(CounterName.named("dummy"), AggregationKind.SUM); + ElementByteSizeObserver observer = new ElementByteSizeObserver(counter); + for (BigInteger value : TEST_VALUES) { + TEST_CODER.registerByteSizeObserver(value, observer, Coder.Context.OUTER); + observer.advance(); + assertThat( + counter.getAggregate(), + equalTo((long) CoderUtils.encodeToByteArray(TEST_CODER, value).length)); + counter.resetToValue(0L); + } + } + + @Test + public void encodeNullThrowsCoderException() throws Exception { + thrown.expect(NullPointerException.class); + thrown.expectMessage("cannot encode a null BigInteger"); + + CoderUtils.encodeToBase64(TEST_CODER, null); + } + + /** + * This is a change-detector test. If this test fails, then the encoding id of + * {@link BigIntegerCoder} must change. + */ + @Test + public void testCoderIdDependencies() { + assertThat(VarIntCoder.of().getEncodingId(), equalTo("")); + assertThat(ByteArrayCoder.of().getEncodingId(), equalTo("")); + } +}
