com.github.cloudecho.protobuf.converter.SimpleProtobufMessageConverter Maven / Gradle / Ivy
The newest version!
package com.github.cloudecho.protobuf.converter;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import com.github.cloudecho.protobuf.exception.MessageConvertException;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.protobuf.BoolValue;
import com.google.protobuf.ByteString;
import com.google.protobuf.BytesValue;
import com.google.protobuf.DoubleValue;
import com.google.protobuf.FloatValue;
import com.google.protobuf.Int32Value;
import com.google.protobuf.Int64Value;
import com.google.protobuf.Message;
import com.google.protobuf.ProtocolMessageEnum;
import com.google.protobuf.StringValue;
import com.google.protobuf.Timestamp;
import com.google.protobuf.UInt32Value;
import com.google.protobuf.UInt64Value;
public class SimpleProtobufMessageConverter implements ProtobufMessageConverter {
private static final Logger logger = LoggerFactory.getLogger(SimpleProtobufMessageConverter.class);
@Override
public Map toProperties(Message message) {
Map result = new HashMap<>();
for (Method getter : getMessageGetterList(message.getClass()).values()) {
String getterName = getter.getName();
if (!maybeMessageValuePresent(message, getterName)) {
continue;
}
Object value;
try {
value = getter.invoke(message);
} catch (Exception ex) {
throw new MessageConvertException(
String.format("invoke getter \"%s\" on an object of type of \"%s\" fail",
getterName, message.getClass().getName()), ex);
}
value = toPropertyValue(value);
if (value == null || (value instanceof Collection && CollectionUtils.isEmpty((Collection>) value))) {
continue;
}
String propertyKey = toPropertyKey(getter);
result.put(propertyKey, value);
}
return result;
}
@Override
public Message.Builder
newMessageBuilder(Class messageType, Map properties) {
Message.Builder builder = newMessageBuilder(messageType);
for (Map.Entry entry : properties.entrySet()) {
Optional setter = getMessageSetterMethod(entry.getKey(), builder);
if (!setter.isPresent()) {
continue;
}
buildMessageAttribute(builder, setter.get(), entry.getValue());
}
return builder;
}
/**
* Convert the getter name to property key .
* e.g. getName -> name, getMyName -> myName
*/
protected String toPropertyKey(String getterName) {
int n = GETTER_PREFIX.length();
return Character.toLowerCase(getterName.charAt(n))
+ getterName.substring(n + 1);
}
/**
* Convert the protobuf message attribute value to property value
*/
protected Object toPropertyValue(Object value) {
if (value instanceof ProtocolMessageEnum) {
return ((ProtocolMessageEnum) value).getNumber();
} else if (value instanceof String) {
String v = (String) value;
return StringUtils.hasLength(v) ? v : null;
} else if (value instanceof ByteString) {
return unwrap((ByteString) value);
} else if (value instanceof List) {
return toPropertyValueOf((List) value);
} else if (value instanceof Timestamp) {
return toDate((Timestamp) value);
} else if (value instanceof DoubleValue) {
return ((DoubleValue) value).getValue();
} else if (value instanceof FloatValue) {
return ((FloatValue) value).getValue();
} else if (value instanceof Int64Value) {
return ((Int64Value) value).getValue();
} else if (value instanceof UInt64Value) {
return ((UInt64Value) value).getValue();
} else if (value instanceof Int32Value) {
return ((Int32Value) value).getValue();
} else if (value instanceof UInt32Value) {
return ((UInt32Value) value).getValue();
} else if (value instanceof BoolValue) {
return ((BoolValue) value).getValue();
} else if (value instanceof StringValue) {
return ((StringValue) value).getValue();
} else if (value instanceof BytesValue) {
return ((BytesValue) value).getValue();
} else if (value instanceof Message) {
return toProperties((Message) value);
} else {
return value;
}
}
/**
* Convert the property key to the setter name.
* e.g. name -> setName
*/
protected String toMessageSetterName(String propertyKey) {
return SETTER_PREFIX
+ Character.toUpperCase(propertyKey.charAt(0))
+ propertyKey.substring(1);
}
/**
* Convert the given {@code value} to a specified {@code targetType} object
*/
@SuppressWarnings({"unchecked"})
protected Object toMessageValue(Type targetType, Object value) {
if (value == null) {
return null;
}
if (String.class.equals(targetType)) {
if (value instanceof byte[]) {
return new String((byte[]) value, Charset.defaultCharset());
}
return String.valueOf(value);
} else if (Timestamp.class.equals(targetType)) {
return toTimestamp(value);
} else if (DoubleValue.class.equals(targetType)) {
return DoubleValue.of(castToNumber(value).doubleValue());
} else if (FloatValue.class.equals(targetType)) {
return FloatValue.of(castToNumber(value).floatValue());
} else if (Int64Value.class.equals(targetType)) {
return Int64Value.of(castToNumber(value).longValue());
} else if (UInt64Value.class.equals(targetType)) {
return UInt64Value.of(castToNumber(value).longValue());
} else if (Int32Value.class.equals(targetType)) {
return Int32Value.of(castToNumber(value).intValue());
} else if (UInt32Value.class.equals(targetType)) {
return UInt32Value.of(castToNumber(value).intValue());
} else if (BoolValue.class.equals(targetType)) {
return BoolValue.of(toBool(value));
} else if (StringValue.class.equals(targetType)) {
return StringValue.of(String.valueOf(value));
} else if (BytesValue.class.equals(targetType)) {
return BytesValue.of(toByteString(value));
} else if (ByteString.class.equals(targetType)) {
return toByteString(value);
} else if (targetType instanceof ParameterizedType) {
return toListMessageValue(LIST_COMPONENT_TYPE_CACHE.get(targetType.getTypeName()), value);
} else if (long.class.equals(targetType) || Long.class.equals(targetType)) {
return castToNumber(value).longValue();
} else if (int.class.equals(targetType) || Integer.class.equals(targetType)) {
return castToNumber(value).intValue();
} else if (Message.class.isAssignableFrom((Class>) targetType)) {
if (value instanceof Map) {
return buildMessage((Class) targetType, (Map) value);
} else {
throw new MessageConvertException(
String.format("Expect a Map value but got %s, targetType: %s",
value.getClass().getName(), targetType.getTypeName()));
}
}
return value;
}
protected boolean maybeMessageGetter(Method method) {
String name = method.getName();
return name.startsWith(GETTER_PREFIX)
&& !name.endsWith(BUILDER_SUFFIX)
&& !name.endsWith(BUILDER_SUFFIX + LIST_SUFFIX)
&& method.getParameterCount() == 0
&& !PROTOBUF_INTERNAL_METHODS.contains(name);
}
protected boolean maybeMessageValuePresent(Message message, String getterName) {
Optional hasserMethod = getHasserMethod(message.getClass(), getterName);
if (!hasserMethod.isPresent()) {
// if the has-method does not exist
return true;
}
try {
return (boolean) hasserMethod.get().invoke(message);
} catch (Exception e) {
throw new MessageConvertException(e);
}
}
protected final Cache> MESSAGE_HASSER_CACHE = CacheBuilder.newBuilder().build();
protected Optional getHasserMethod(Class> messageClass, String getterName) {
final String key = getterName + "@" + messageClass.getName();
try {
return MESSAGE_HASSER_CACHE.get(key, () -> getHasserMethod0(messageClass, getterName));
} catch (ExecutionException e) {
throw new MessageConvertException(e);
}
}
protected Optional getHasserMethod0(Class> messageClass, String getterName) {
try {
Method hasser = messageClass.getDeclaredMethod(
HASSER_PREFIX + getterName.substring(GETTER_PREFIX.length()));
//if has-method exists
logger.debug("has-method exists: {}, message type: {}", getterName, messageClass.getName());
return Optional.of(hasser);
} catch (NoSuchMethodException e) {
return Optional.empty();
}
}
protected String toPropertyKey(Method getter) {
String getterName = getter.getName();
if (List.class.isAssignableFrom(getter.getReturnType())) {
if (getterName.endsWith(LIST_SUFFIX)) {
getterName = getterName.substring(0, getterName.length() - LIST_SUFFIX.length());
}
}
return toPropertyKey(getterName);
}
protected List © 2015 - 2025 Weber Informatics LLC | Privacy Policy