
com.hazelcast.internal.serialization.impl.compact.CompactUtil Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2008-2024, Hazelcast, Inc. All Rights Reserved.
*
* Licensed 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 com.hazelcast.internal.serialization.impl.compact;
import com.hazelcast.nio.serialization.FieldKind;
import com.hazelcast.nio.serialization.HazelcastSerializationException;
import javax.annotation.Nonnull;
import java.lang.reflect.Array;
/**
* Utility methods to be used in compact serialization
*/
public final class CompactUtil {
// To determine classes that we won't serialize with zero-config serialization
private static final UnsupportedPackagePrefix[] UNSUPPORTED_PACKAGE_PREFIXES = new UnsupportedPackagePrefix[]{
new UnsupportedPackagePrefix("java"),
new UnsupportedPackagePrefix("javax"),
new UnsupportedPackagePrefix("com.sun"),
new UnsupportedPackagePrefix("sun"),
new UnsupportedPackagePrefix("jdk")
};
private CompactUtil() {
}
@Nonnull
public static HazelcastSerializationException exceptionForUnexpectedNullValue(@Nonnull String fieldName,
@Nonnull String methodPrefix,
@Nonnull String methodSuffix) {
return new HazelcastSerializationException("Error while reading " + fieldName + ". "
+ "null value can not be read via " + methodPrefix + methodSuffix + " methods. "
+ "Use " + methodPrefix + "Nullable" + methodSuffix + " instead.");
}
@Nonnull
public static HazelcastSerializationException exceptionForUnexpectedNullValueInArray(@Nonnull String fieldName,
@Nonnull String methodPrefix,
@Nonnull String methodSuffix) {
return new HazelcastSerializationException("Error while reading " + fieldName + ". "
+ "null value can not be read via " + methodPrefix + "ArrayOf" + methodSuffix + " methods. "
+ "Use " + methodPrefix + "ArrayOfNullable" + methodSuffix + " instead.");
}
public static boolean isFieldExist(Schema schema, String fieldName, FieldKind fieldKind) {
FieldDescriptor field = schema.getField(fieldName);
if (field == null) {
return false;
}
return field.getKind() == fieldKind;
}
public static boolean isFieldExist(Schema schema, String fieldName, FieldKind fieldKind, FieldKind compatibleFieldKind) {
FieldDescriptor field = schema.getField(fieldName);
if (field == null) {
return false;
}
return field.getKind() == fieldKind || field.getKind() == compatibleFieldKind;
}
public static Enum enumFromStringName(Class extends Enum> enumClass, String name) {
if (name == null) {
return null;
}
return Enum.valueOf(enumClass, name);
}
public static String enumAsStringName(Enum e) {
if (e == null) {
return null;
}
return e.name();
}
public static String[] enumArrayAsStringNameArray(Enum[] enumArray) {
if (enumArray == null) {
return null;
}
String[] stringArray = new String[enumArray.length];
for (int i = 0; i < enumArray.length; i++) {
stringArray[i] = enumAsStringName(enumArray[i]);
}
return stringArray;
}
public static Enum[] enumArrayFromStringNameArray(Class extends Enum> enumClass, String[] stringArray) {
if (stringArray == null) {
return null;
}
Enum[] enumArray = (Enum[]) Array.newInstance(enumClass, stringArray.length);
for (int i = 0; i < stringArray.length; i++) {
enumArray[i] = enumFromStringName(enumClass, stringArray[i]);
}
return enumArray;
}
public static Character characterFromShort(Short s) {
if (s == null) {
return null;
}
return (char) s.shortValue();
}
public static Short characterAsShort(Character c) {
if (c == null) {
return null;
}
return (short) c.charValue();
}
public static char[] charArrayFromShortArray(short[] shortArray) {
if (shortArray == null) {
return null;
}
char[] charArray = new char[shortArray.length];
for (int i = 0; i < shortArray.length; i++) {
charArray[i] = (char) shortArray[i];
}
return charArray;
}
public static short[] charArrayAsShortArray(char[] charArray) {
if (charArray == null) {
return null;
}
short[] shortArray = new short[charArray.length];
for (int i = 0; i < charArray.length; i++) {
shortArray[i] = (short) charArray[i];
}
return shortArray;
}
public static Character[] characterArrayFromShortArray(Short[] shortArray) {
if (shortArray == null) {
return null;
}
Character[] characterArray = new Character[shortArray.length];
for (int i = 0; i < shortArray.length; i++) {
characterArray[i] = characterFromShort(shortArray[i]);
}
return characterArray;
}
public static Short[] characterArrayAsShortArray(Character[] characterArray) {
if (characterArray == null) {
return null;
}
Short[] shortArray = new Short[characterArray.length];
for (int i = 0; i < characterArray.length; i++) {
shortArray[i] = characterAsShort(characterArray[i]);
}
return shortArray;
}
public static void verifyClassIsCompactSerializable(Class> clazz) {
if (canBeSerializedAsCompact(clazz)) {
return;
}
throw new HazelcastSerializationException("The '" + clazz + "' cannot "
+ "be serialized with zero configuration Compact serialization "
+ "because this type is not supported yet. If you want to "
+ "serialize this class, consider writing a CompactSerializer "
+ "for it.");
}
public static void verifyFieldClassIsCompactSerializable(Class> fieldClass, Class> clazz) {
if (canBeSerializedAsCompact(fieldClass)) {
return;
}
throw new HazelcastSerializationException("The '" + fieldClass + "' "
+ "cannot be serialized with zero configuration Compact "
+ "serialization because this type is not supported yet. If you "
+ "want to serialize '" + clazz + "' which uses this class in "
+ "its fields, consider writing a CompactSerializer for either the '"
+ clazz + "' or the '" + fieldClass + "'.");
}
public static void verifyFieldClassShouldBeSerializedAsCompact(CompactStreamSerializer compactStreamSerializer,
Class> fieldClass, Class> clazz) {
if (compactStreamSerializer.canBeSerializedAsCompact(fieldClass)) {
return;
}
throw new HazelcastSerializationException("The '" + fieldClass + "' "
+ "cannot be serialized with zero configuration Compact "
+ "serialization because this type can be serialized with another "
+ "serialization mechanism. If you want to serialize "
+ "'" + clazz + "' which uses this class in its fields, consider "
+ "overriding that serialization mechanism. You can do that by "
+ "adding '" + fieldClass + "' to CompactSerializationConfig, or "
+ "writing and registering an explicit CompactSerializer for it.");
}
private static boolean canBeSerializedAsCompact(Class> clazz) {
Package classPackage = clazz.getPackage();
if (classPackage == null) {
// If the Java version is 8, we can hit this branch if the user
// class does not have a package defined for it (the default
// package). In Java 9 and above, in that case, we won't hit this,
// but it will return a package whose name is an empty string.
// In Java 9 and above, the method returns null if the class is
// primitive, array or Void.
// We won't hit this line for primitive types, as they are already
// supported by the reflective serializers. For arrays, we can only
// hit this line for arrays of arrays which is not supported by
// Compact. And, Void is not a type we support in the Compact
// serialization.
// So, we can return false here, if the clazz is one of the types
// mentioned above, and return true if not, to be able to serialize
// user classes without a package in Java 8.
return !clazz.isPrimitive() && !clazz.isArray() && !Void.class.equals(clazz);
}
String name = classPackage.getName();
for (UnsupportedPackagePrefix prefix : UNSUPPORTED_PACKAGE_PREFIXES) {
if (prefix.matches(name)) {
return false;
}
}
return true;
}
/**
* This class is used to check if the given package name can be supported
* with the zero-config Compact serialization, by trying to check if the
* given package name is one of the known JDK package prefixes.
*/
private static final class UnsupportedPackagePrefix {
private final String prefix;
private final String prefixWithDot;
private UnsupportedPackagePrefix(String prefix) {
this.prefix = prefix;
this.prefixWithDot = prefix + ".";
}
/**
* Returns {@code true} if the given package name
*
* - starts with the unsupported {@code prefix + "."}, hence
* under some package with the given prefix
* - equals to the {@code prefix}, hence directly in the
* given package
*
*
* The extra logic is to prevent falsely identifying packages which
* starts with the given unsupported package name prefix like
* {@code java_but_not_really_jdk}.
*/
public boolean matches(String packageName) {
return packageName.startsWith(prefixWithDot) || packageName.equals(prefix);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy