From c49cdc3e61bcf39d79273498200e0a263b687a31 Mon Sep 17 00:00:00 2001 From: Duo Zhang Date: Wed, 16 Jan 2019 18:38:58 +0800 Subject: [PATCH] HBASE-21732 Should call toUpperCase before using Enum.valueOf in some methods for ColumnFamilyDescriptor Signed-off-by: Zheng Hu --- .../client/ColumnFamilyDescriptorBuilder.java | 30 ++--- ...stColumnFamilyDescriptorLowerCaseEnum.java | 104 ++++++++++++++++++ 2 files changed, 119 insertions(+), 15 deletions(-) create mode 100644 hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestColumnFamilyDescriptorLowerCaseEnum.java diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ColumnFamilyDescriptorBuilder.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ColumnFamilyDescriptorBuilder.java index d7feea62d21..da7bdda3ccb 100644 --- a/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ColumnFamilyDescriptorBuilder.java +++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/client/ColumnFamilyDescriptorBuilder.java @@ -17,7 +17,6 @@ */ package org.apache.hadoop.hbase.client; -import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; import java.io.IOException; import java.util.Collections; import java.util.HashMap; @@ -25,21 +24,23 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.function.Function; - import org.apache.hadoop.hbase.HConstants; import org.apache.hadoop.hbase.KeepDeletedCells; import org.apache.hadoop.hbase.MemoryCompactionPolicy; -import org.apache.yetus.audience.InterfaceAudience; import org.apache.hadoop.hbase.exceptions.DeserializationException; import org.apache.hadoop.hbase.exceptions.HBaseException; import org.apache.hadoop.hbase.io.compress.Compression; import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding; import org.apache.hadoop.hbase.regionserver.BloomType; -import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; -import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ColumnFamilySchema; import org.apache.hadoop.hbase.util.Bytes; import org.apache.hadoop.hbase.util.PrettyPrinter; import org.apache.hadoop.hbase.util.PrettyPrinter.Unit; +import org.apache.yetus.audience.InterfaceAudience; + +import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; + +import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil; +import org.apache.hadoop.hbase.shaded.protobuf.generated.HBaseProtos.ColumnFamilySchema; /** * @since 2.0.0 @@ -129,7 +130,6 @@ public class ColumnFamilyDescriptorBuilder { private static final Bytes BLOOMFILTER_BYTES = new Bytes(Bytes.toBytes(BLOOMFILTER)); @InterfaceAudience.Private public static final String REPLICATION_SCOPE = "REPLICATION_SCOPE"; - private static final Bytes REPLICATION_SCOPE_BYTES = new Bytes(Bytes.toBytes(REPLICATION_SCOPE)); @InterfaceAudience.Private public static final String MAX_VERSIONS = HConstants.VERSIONS; private static final Bytes MAX_VERSIONS_BYTES = new Bytes(Bytes.toBytes(MAX_VERSIONS)); @@ -778,8 +778,7 @@ public class ColumnFamilyDescriptorBuilder { @Override public Compression.Algorithm getCompressionType() { return getStringOrDefault(COMPRESSION_BYTES, - Compression.Algorithm::valueOf, - DEFAULT_COMPRESSION); + n -> Compression.Algorithm.valueOf(n.toUpperCase()), DEFAULT_COMPRESSION); } /** @@ -799,8 +798,7 @@ public class ColumnFamilyDescriptorBuilder { @Override public DataBlockEncoding getDataBlockEncoding() { return getStringOrDefault(DATA_BLOCK_ENCODING_BYTES, - DataBlockEncoding::valueOf, - DataBlockEncoding.NONE); + n -> DataBlockEncoding.valueOf(n.toUpperCase()), DataBlockEncoding.NONE); } /** @@ -833,8 +831,7 @@ public class ColumnFamilyDescriptorBuilder { @Override public Compression.Algorithm getCompactionCompressionType() { return getStringOrDefault(COMPRESSION_COMPACT_BYTES, - Compression.Algorithm::valueOf, - getCompressionType()); + n -> Compression.Algorithm.valueOf(n.toUpperCase()), getCompressionType()); } /** @@ -868,7 +865,8 @@ public class ColumnFamilyDescriptorBuilder { @Override public MemoryCompactionPolicy getInMemoryCompaction() { - return getStringOrDefault(IN_MEMORY_COMPACTION_BYTES, MemoryCompactionPolicy::valueOf, null); + return getStringOrDefault(IN_MEMORY_COMPACTION_BYTES, + n -> MemoryCompactionPolicy.valueOf(n.toUpperCase()), null); } /** @@ -962,7 +960,8 @@ public class ColumnFamilyDescriptorBuilder { @Override public BloomType getBloomFilterType() { - return getStringOrDefault(BLOOMFILTER_BYTES, BloomType::valueOf, DEFAULT_BLOOMFILTER); + return getStringOrDefault(BLOOMFILTER_BYTES, n -> BloomType.valueOf(n.toUpperCase()), + DEFAULT_BLOOMFILTER); } public ModifyableColumnFamilyDescriptor setBloomFilterType(final BloomType bt) { @@ -1302,7 +1301,8 @@ public class ColumnFamilyDescriptorBuilder { @Override public MobCompactPartitionPolicy getMobCompactPartitionPolicy() { return getStringOrDefault(MOB_COMPACT_PARTITION_POLICY_BYTES, - MobCompactPartitionPolicy::valueOf, DEFAULT_MOB_COMPACT_PARTITION_POLICY); + n -> MobCompactPartitionPolicy.valueOf(n.toUpperCase()), + DEFAULT_MOB_COMPACT_PARTITION_POLICY); } /** diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestColumnFamilyDescriptorLowerCaseEnum.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestColumnFamilyDescriptorLowerCaseEnum.java new file mode 100644 index 00000000000..ac8aed866e6 --- /dev/null +++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestColumnFamilyDescriptorLowerCaseEnum.java @@ -0,0 +1,104 @@ +/** + * 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.hadoop.hbase.client; + +import static org.junit.Assert.assertEquals; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; +import java.util.NoSuchElementException; +import org.apache.hadoop.hbase.HBaseClassTestRule; +import org.apache.hadoop.hbase.testclassification.ClientTests; +import org.apache.hadoop.hbase.testclassification.SmallTests; +import org.apache.hadoop.hbase.util.Bytes; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Testcase for HBASE-21732. Make sure that all enum configurations can accept lower case value. + */ +@Category({ ClientTests.class, SmallTests.class }) +public class TestColumnFamilyDescriptorLowerCaseEnum { + + @ClassRule + public static final HBaseClassTestRule CLASS_RULE = + HBaseClassTestRule.forClass(TestColumnFamilyDescriptorLowerCaseEnum.class); + + private static final Logger LOG = + LoggerFactory.getLogger(TestColumnFamilyDescriptorLowerCaseEnum.class); + + private Method getSetMethod(Method getMethod, Class enumType) throws NoSuchMethodException { + String methodName = getMethod.getName().replaceFirst("get", "set"); + return ColumnFamilyDescriptorBuilder.class.getMethod(methodName, enumType); + } + + private Enum getEnumValue(Class enumType) { + for (Enum enumConst : enumType.asSubclass(Enum.class).getEnumConstants()) { + if (!enumConst.name().equalsIgnoreCase("NONE") && !enumConst.name().equals("DEFAULT")) { + return enumConst; + } + } + throw new NoSuchElementException(enumType.getName()); + } + + private boolean contains(Collection> enumConsts, String value) { + return enumConsts.stream().anyMatch(e -> e.name().equals(value)); + } + + @Test + public void test() + throws IllegalAccessException, InvocationTargetException, NoSuchMethodException { + Map> getMethod2Value = new HashMap<>(); + ColumnFamilyDescriptorBuilder builder = + ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("test")); + for (Method method : ColumnFamilyDescriptor.class.getMethods()) { + if (method.getParameterCount() == 0 && method.getReturnType().isEnum()) { + LOG.info("Checking " + method); + Class enumType = method.getReturnType(); + Method setMethod = getSetMethod(method, enumType); + Enum enumConst = getEnumValue(enumType); + LOG.info("Using " + setMethod + " to set the value to " + enumConst); + setMethod.invoke(builder, enumConst); + getMethod2Value.put(method, enumConst); + } + } + ColumnFamilyDescriptor desc = builder.build(); + ColumnFamilyDescriptorBuilder builder2 = + ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes("test2")); + desc.getValues().forEach((k, v) -> { + LOG.info(k.toString() + "=>" + v.toString()); + String str = Bytes.toString(v.get(), v.getOffset(), v.getLength()); + if (contains(getMethod2Value.values(), str)) { + LOG.info("Set to lower case " + str.toLowerCase()); + builder2.setValue(k, new Bytes(Bytes.toBytes(str.toLowerCase()))); + } + }); + + ColumnFamilyDescriptor desc2 = builder2.build(); + for (Map.Entry> entry : getMethod2Value.entrySet()) { + assertEquals(entry.getKey() + " should return " + entry.getValue(), entry.getValue(), + entry.getKey().invoke(desc2)); + } + } +}