org.apache.kafka.connect.data.Decimal Maven / Gradle / Ivy
/*
* 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.kafka.connect.data;
import org.apache.kafka.connect.errors.DataException;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
*
* An arbitrary-precision signed decimal number. The value is unscaled * 10 ^ -scale where:
*
* - unscaled is an integer
* - scale is an integer representing how many digits the decimal point should be shifted on the unscaled value
*
*
*
* Decimal does not provide a fixed schema because it is parameterized by the scale, which is fixed on the schema
* rather than being part of the value.
*
*
* The underlying representation of this type is bytes containing a two's complement integer
*
*/
public class Decimal {
public static final String LOGICAL_NAME = "org.apache.kafka.connect.data.Decimal";
public static final String SCALE_FIELD = "scale";
/**
* Returns a SchemaBuilder for a Decimal with the given scale factor. By returning a SchemaBuilder you can override
* additional schema settings such as required/optional, default value, and documentation.
* @param scale the scale factor to apply to unscaled values
* @return a SchemaBuilder
*/
public static SchemaBuilder builder(int scale) {
return SchemaBuilder.bytes()
.name(LOGICAL_NAME)
.parameter(SCALE_FIELD, Integer.toString(scale))
.version(1);
}
public static Schema schema(int scale) {
return builder(scale).build();
}
/**
* Convert a value from its logical format ({@link BigDecimal}) to its encoded format (byte[]).
* @param value the logical value
* @return the encoded value
*/
public static byte[] fromLogical(Schema schema, BigDecimal value) {
int schemaScale = scale(schema);
if (value.scale() != schemaScale)
throw new DataException(String.format(
"Decimal value has mismatching scale for given Decimal schema. "
+ "Schema has scale %d, value has scale %d.",
schemaScale,
value.scale()
));
return value.unscaledValue().toByteArray();
}
/**
* Convert a value from its encoded format (byte[]) to its logical format ({@link BigDecimal}).
* @param value the encoded value
* @return the logical value
*/
public static BigDecimal toLogical(Schema schema, byte[] value) {
return new BigDecimal(new BigInteger(value), scale(schema));
}
private static int scale(Schema schema) {
String scaleString = schema.parameters().get(SCALE_FIELD);
if (scaleString == null)
throw new DataException("Invalid Decimal schema: scale parameter not found.");
try {
return Integer.parseInt(scaleString);
} catch (NumberFormatException e) {
throw new DataException("Invalid scale parameter found in Decimal schema: ", e);
}
}
}