An experiment using a custom Annotation to repurpose Javadocs as a multiline String.
Copyright © 2023 Taeber Rapczak <[email protected]>. License: MIT.
make
Building protobuf messages in Java is a bit tedious, especially when the message is complex and the values you're setting are few.
If I was given this template and asked to implement it:
subject: {
id: ${agentId}
}
predicate: KNOWS
object: {
name: ${fullname}
}
I'd probably write something like:
Expression expr =
Expression.newBuilder()
.setSubject(Thing.newBuilder().setId(agentId))
.setPredicate(Predicate.KNOWS)
.setObject(Thing.newBuilder().setName(fullname))
.build();
Honestly, not bad once you get used to it and if you have an ML-assisted editor, you probably wouldn't think twice.
I've dealt with much more complex messages and wished that I could just use
String.format
with the template I was given, but alas there was no multiline
string literal support in Java before Java 13
(JEP-355), so it becomes:
String msg = String.format(
"subject: { " +
" id: %d " +
"} " +
"predicate: KNOWS" +
"object: { " +
" name: %s " +
"} ",
006, "James Bond");
With the Annotation ProtobufTemplate
and a custom Processor, you could
instead write:
/**
subject: {
id: ${agentId}
}
predicate: KNOWS
object: {
name: "${fullname}"
}
*/
@ProtobufTemplate("AgentKnowsAgentTemplate")
private static Expression buildAgentKnowsAgent(long agentId, String fullname) {
return AgentKnowsAgentTemplate.format(agentId, fullname);
}
I originally had thought to generate the Builder code, but so far I'm still
using com.google.protobuf.TextFormat
.
Here's some sample generated output:
// THIS FILE WAS GENERATED by ProtobufTemplateProcessor.
package com.rapczak.taeber.protobuf;
import com.google.protobuf.TextFormat;
final class AgentKnowsAgentTemplate {
private static String msg = "subject: {\n id: ${agentId}\n }\n predicate: KNOWS\n object: {\n name: \"${fullname}\"\n }";
public static com.rapczak.taeber.protobuf.Expression format(long agentId,java.lang.String fullname) {
var builder = com.rapczak.taeber.protobuf.Expression.newBuilder();
String[] placeholders = {"agentId","fullname"};
String[] replacements = {String.valueOf(agentId),fullname.toString()};
var txt = msg;
for (var i = 0; i < placeholders.length; i++) {
txt = txt.replace("${" + placeholders[i] + "}", replacements[i]);
}
try {TextFormat.getParser().merge(txt, builder);}
catch (Exception e) {throw new RuntimeException(e);}
return builder.build();
}
private AgentKnowsAgentTemplate() {}
}