
org.openbase.jul.extension.protobuf.ProtoBufBuilderProcessor.kt Maven / Gradle / Ivy
The newest version!
package org.openbase.jul.extension.protobuf
import com.google.protobuf.AbstractMessage
import com.google.protobuf.Descriptors
import com.google.protobuf.Message
import com.google.protobuf.MessageOrBuilder
import org.openbase.jul.exception.CouldNotPerformException
import org.openbase.jul.exception.NotAvailableException
import org.openbase.jul.extension.protobuf.processing.ProtoBufFieldProcessor
import org.openbase.jul.processing.StringProcessor
import java.lang.reflect.Method
/*
* #%L
* JUL Extension Protobuf
* %%
* Copyright (C) 2015 - 2022 openbase.org
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Lesser Public License for more details.
*
* You should have received a copy of the GNU General Lesser Public
* License along with this program. If not, see
* .
* #L%
*/ /**
* * @author DivineThreepwood
*/
object ProtoBufBuilderProcessor {
@Throws(CouldNotPerformException::class)
@JvmStatic
fun extractRepeatedFieldBuilderList(repeatedFieldNumber: Int, builder: Message.Builder): List {
return extractRepeatedFieldBuilderList(
builder.descriptorForType.findFieldByNumber(repeatedFieldNumber),
builder
)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun extractRepeatedFieldBuilderList(
repeatedFieldDescriptor: Descriptors.FieldDescriptor?,
builder: Message.Builder
): List {
if (repeatedFieldDescriptor == null) {
throw NotAvailableException("repeatedFieldDescriptor")
}
return extractRepeatedFieldBuilderList(repeatedFieldDescriptor.name, builder)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun extractRepeatedFieldBuilderList(repeatedFieldName: String, builder: Message.Builder): List {
return try {
val builderClass: Class<*> = builder.javaClass
val method: Method
method = try {
builderClass.getMethod("get" + StringProcessor.transformUpperCaseToPascalCase(repeatedFieldName) + "BuilderList")
} catch (ex: Exception) {
throw CouldNotPerformException(
"Missing RepeatedField[" + repeatedFieldName + "] in protobuf Type[" + builder.javaClass.name + "]! ",
ex
)
}
try {
method.invoke(builder) as List
} catch (ex: Exception) {
throw CouldNotPerformException("Could not extract builder list!", ex)
}
} catch (ex: Exception) {
throw CouldNotPerformException(
"Could extract builder collection out of Builder[" + builder.javaClass.name + "]!",
ex
)
}
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addMessageToRepeatedField(
repeatedFieldNumber: Int,
messageBuilder: Message.Builder,
builder: Message.Builder
): Message.Builder {
return addMessageToRepeatedField(
builder.descriptorForType.findFieldByNumber(repeatedFieldNumber),
messageBuilder,
builder
)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addMessageToRepeatedField(
repeatedFieldDescriptor: Descriptors.FieldDescriptor?,
messageBuilder: Message.Builder,
builder: Message.Builder
): Message.Builder {
if (repeatedFieldDescriptor == null) {
throw NotAvailableException("repeatedFieldDescriptor")
}
return addMessageToRepeatedField(repeatedFieldDescriptor.name, messageBuilder, builder)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addMessageToRepeatedField(
repeatedFieldName: String,
messageBuilder: Message.Builder,
builder: Message.Builder
): Message.Builder {
return try {
val builderClass: Class<*> = builder.javaClass
val method: Method
method = try {
builderClass.getMethod(
"add" + StringProcessor.transformUpperCaseToPascalCase(repeatedFieldName),
messageBuilder.javaClass
)
} catch (ex: Exception) {
throw CouldNotPerformException(
"Missing RepeatedField[" + repeatedFieldName + "] in protobuf Type[" + builder.javaClass.name + "]! ",
ex
)
}
try {
method.invoke(builder, messageBuilder)
} catch (ex: Exception) {
throw CouldNotPerformException("Could not add message builder to repeated field!", ex)
}
builder
} catch (ex: Exception) {
throw CouldNotPerformException(
"Could add message Builder[" + messageBuilder.javaClass.name + "] to repeated Field[" + repeatedFieldName + "] of Builder[" + builder.javaClass.name + "]!",
ex
)
}
}
/**
* Method adds a new default message instance to the repeated field and return it's builder instance.
*
* @param repeatedFieldNumber The field number of the repeated field.
* @param builder The builder instance of the message which contains the repeated field.
* @return The builder instance of the new added message is returned.
* @throws CouldNotPerformException
*/
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addDefaultInstanceToRepeatedField(repeatedFieldNumber: Int, builder: Message.Builder): Message.Builder {
return addDefaultInstanceToRepeatedField(
builder.descriptorForType.findFieldByNumber(repeatedFieldNumber),
builder
)
}
/**
* Method adds a new default message instance to the repeated field and return it's builder instance.
*
* @param repeatedFieldDescriptor The field descriptor of the repeated field.
* @param builder The builder instance of the message which contains the repeated field.
* @return The builder instance of the new added message is returned.
* @throws CouldNotPerformException
*/
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addDefaultInstanceToRepeatedField(
repeatedFieldDescriptor: Descriptors.FieldDescriptor?,
builder: Message.Builder
): Message.Builder {
if (repeatedFieldDescriptor == null) {
throw NotAvailableException("repeatedFieldDescriptor")
}
return addDefaultInstanceToRepeatedField(repeatedFieldDescriptor.name, builder)
}
/**
* Method adds a new default message instance to the repeated field and return it's builder instance.
*
* @param repeatedFieldName The name of the repeated field.
* @param builder The builder instance of the message which contains the repeated field.
* @return The builder instance of the new added message is returned.
* @throws CouldNotPerformException
*/
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addDefaultInstanceToRepeatedField(repeatedFieldName: String, builder: Message.Builder): Message.Builder {
return try {
val builderClass: Class<*> = builder.javaClass
val method: Method
method = try {
builderClass.getMethod("add" + StringProcessor.transformUpperCaseToPascalCase(repeatedFieldName) + "Builder")
} catch (ex: Exception) {
throw CouldNotPerformException(
"Missing RepeatedField[" + repeatedFieldName + "] in protobuf Type[" + builder.javaClass.name + "]! ",
ex
)
}
try {
method.invoke(builder) as Message.Builder
} catch (ex: Exception) {
throw CouldNotPerformException("Could not add default message builder to repeated field!", ex)
}
} catch (ex: Exception) {
throw CouldNotPerformException(
"Could add default instance to repeated Field[" + repeatedFieldName + "] of Builder[" + builder.javaClass.name + "]!",
ex
)
}
}
//TODO: all methods below are copies using AbstractMessage instead of message, I think they can be removed as soon as the new registry editor is usable
@Throws(CouldNotPerformException::class)
@JvmStatic
fun extractRepeatedFieldBuilderList(
repeatedFieldNumber: Int,
builder: AbstractMessage.Builder<*>
): List> {
return extractRepeatedFieldBuilderList(
builder.descriptorForType.findFieldByNumber(repeatedFieldNumber),
builder
)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun extractRepeatedFieldBuilderList(
repeatedFieldDescriptor: Descriptors.FieldDescriptor?,
builder: AbstractMessage.Builder<*>
): List> {
if (repeatedFieldDescriptor == null) {
throw NotAvailableException("repeatedFieldDescriptor")
}
return extractRepeatedFieldBuilderList(repeatedFieldDescriptor.name, builder)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun extractRepeatedFieldBuilderList(
repeatedFieldName: String,
builder: AbstractMessage.Builder<*>
): List> {
return try {
val builderClass: Class<*> = builder.javaClass
val method: Method
method = try {
builderClass.getMethod("get" + StringProcessor.transformUpperCaseToPascalCase(repeatedFieldName) + "BuilderList")
} catch (ex: Exception) {
throw CouldNotPerformException(
"Missing RepeatedField[" + repeatedFieldName + "] in protobuf Type[" + builder.javaClass.name + "]! ",
ex
)
}
try {
method.invoke(builder) as List>
} catch (ex: Exception) {
throw CouldNotPerformException("Could not extract builder list!", ex)
}
} catch (ex: Exception) {
throw CouldNotPerformException(
"Could extract builder collection out of Builder[" + builder.javaClass.name + "]!",
ex
)
}
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addMessageToRepeatedField(
repeatedFieldNumber: Int,
messageBuilder: AbstractMessage.Builder<*>,
builder: AbstractMessage.Builder<*>
): AbstractMessage.Builder<*> {
return addMessageToRepeatedField(
builder.descriptorForType.findFieldByNumber(repeatedFieldNumber),
messageBuilder,
builder
)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addMessageToRepeatedField(
repeatedFieldDescriptor: Descriptors.FieldDescriptor?,
messageBuilder: AbstractMessage.Builder<*>,
builder: AbstractMessage.Builder<*>
): AbstractMessage.Builder<*> {
if (repeatedFieldDescriptor == null) {
throw NotAvailableException("repeatedFieldDescriptor")
}
return addMessageToRepeatedField(repeatedFieldDescriptor.name, messageBuilder, builder)
}
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addMessageToRepeatedField(
repeatedFieldName: String,
messageBuilder: AbstractMessage.Builder<*>,
builder: AbstractMessage.Builder<*>
): AbstractMessage.Builder<*> {
return try {
val builderClass: Class<*> = builder.javaClass
val method: Method
method = try {
builderClass.getMethod(
"add" + StringProcessor.transformUpperCaseToPascalCase(repeatedFieldName),
messageBuilder.javaClass
)
} catch (ex: Exception) {
throw CouldNotPerformException(
"Missing RepeatedField[" + repeatedFieldName + "] in protobuf Type[" + builder.javaClass.name + "]! ",
ex
)
}
try {
method.invoke(builder, messageBuilder)
} catch (ex: Exception) {
throw CouldNotPerformException("Could not add message builder to repeated field!", ex)
}
builder
} catch (ex: Exception) {
throw CouldNotPerformException(
"Could add message Builder[" + messageBuilder.javaClass.name + "] to repeated Field[" + repeatedFieldName + "] of Builder[" + builder.javaClass.name + "]!",
ex
)
}
}
/**
* Method adds a new default message instance to the repeated field and return it's builder instance.
*
* @param repeatedFieldNumber The field number of the repeated field.
* @param builder The builder instance of the message which contains the repeated field.
* @return The builder instance of the new added message is returned.
* @throws CouldNotPerformException
*/
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addDefaultInstanceToRepeatedField(
repeatedFieldNumber: Int,
builder: AbstractMessage.Builder<*>
): AbstractMessage.Builder<*> {
return addDefaultInstanceToRepeatedField(
builder.descriptorForType.findFieldByNumber(repeatedFieldNumber),
builder
)
}
/**
* Method adds a new default message instance to the repeated field and return it's builder instance.
*
* @param repeatedFieldDescriptor The field descriptor of the repeated field.
* @param builder The builder instance of the message which contains the repeated field.
* @return The builder instance of the new added message is returned.
* @throws CouldNotPerformException
*/
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addDefaultInstanceToRepeatedField(
repeatedFieldDescriptor: Descriptors.FieldDescriptor?,
builder: AbstractMessage.Builder<*>
): AbstractMessage.Builder<*> {
if (repeatedFieldDescriptor == null) {
throw NotAvailableException("repeatedFieldDescriptor")
}
return addDefaultInstanceToRepeatedField(repeatedFieldDescriptor.name, builder)
}
/**
* Method adds a new default message instance to the repeated field and return it's builder instance.
*
* @param repeatedFieldName The name of the repeated field.
* @param builder The builder instance of the message which contains the repeated field.
* @return The builder instance of the new added message is returned.
* @throws CouldNotPerformException
*/
@Throws(CouldNotPerformException::class)
@JvmStatic
fun addDefaultInstanceToRepeatedField(
repeatedFieldName: String,
builder: AbstractMessage.Builder<*>
): AbstractMessage.Builder<*> {
return try {
val builderClass: Class<*> = builder.javaClass
val method: Method
method = try {
builderClass.getMethod("add" + StringProcessor.transformUpperCaseToPascalCase(repeatedFieldName) + "Builder")
} catch (ex: Exception) {
throw CouldNotPerformException(
"Missing RepeatedField[" + repeatedFieldName + "] in protobuf Type[" + builder.javaClass.name + "]! ",
ex
)
}
try {
method.invoke(builder) as AbstractMessage.Builder<*>
} catch (ex: Exception) {
throw CouldNotPerformException("Could not add default message builder to repeated field!", ex)
}
} catch (ex: Exception) {
throw CouldNotPerformException(
"Could add default instance to repeated Field[" + repeatedFieldName + "] of Builder[" + builder.javaClass.name + "]!",
ex
)
}
}
/**
* Merge the values of a message or builder into another message.
* This method accepts message of different types and tries to merge all fields
* which have the same field name in both types.
*
* @param mergedInto the builder into which new values are merged
* @param toMerge the message or builder from which values are merged
* @return the builder merged into
*/
@JvmStatic
fun merge(mergedInto: Message.Builder, toMerge: MessageOrBuilder): Message.Builder {
for (toMergeField in toMerge.allFields.keys) {
// Note: getAllFields return only the fields which are not empty
for (mergedIntoField in mergedInto.descriptorForType.fields) {
if (mergedIntoField.name == toMergeField.name) {
mergedInto.setField(mergedIntoField, toMerge.getField(toMergeField))
break
}
}
}
return mergedInto
}
@Throws(NotAvailableException::class)
@JvmStatic
fun getBuilder(builder: Message.Builder, fieldName: String, builderClass: Class?): MB {
return try {
builder.getFieldBuilder(ProtoBufFieldProcessor.getFieldDescriptor(builder, fieldName)) as MB
} catch (ex: Exception) {
throw NotAvailableException("Builder[$fieldName]", ex)
}
}
/**
* This method clears all repeated fields from the given message before the `mergeFrom` is performed.
* This functionality can be useful, since `mergeFrom` would always duplicate all repeated fields
* which can be avoided by using this function instead.
* @param message the message to merge from.
*/
@JvmStatic
fun MB.mergeFromWithoutRepeatedFields(builder: Message.Builder): MB =
// we should not modify the passed builder, so we need to transform it into a message first.
mergeFromWithoutRepeatedFields(builder.build())
/**
* This method clears all repeated fields from the given message before the `mergeFrom` is performed.
* This functionality can be useful, since `mergeFrom` would always duplicate all repeated fields
* which can be avoided by using this function instead.
* @param message the message to merge from.
*/
@JvmStatic
fun MB.mergeFromWithoutRepeatedFields(message: Message): MB =
message.toBuilder()
.let { messageBuilder -> messageBuilder.clearRepeatedFields() }
.let { messageBuilder -> mergeFrom(messageBuilder.build()) as MB }
/**
* This method recursively clears all repeated fields from the builder instance.
*/
@JvmStatic
fun MB.clearRepeatedFields(): MB = also { builder ->
allFields.keys.forEach { descriptor ->
descriptor
.takeIf { it.isRepeated }
?.also {clearField(it) ; return@forEach }
descriptor
.takeIf { it.javaType == Descriptors.FieldDescriptor.JavaType.MESSAGE }
?.also { builder.getFieldBuilder(it).clearRepeatedFields() }
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy