An experiment using a custom Annotation to repurpose Javadocs as a multiline String.
Copyright © 2023 Taeber Rapczak <taeber@rapczak.com>. 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() {} }