Skip to content

taeber/java-multiline

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Java Multiline Strings

An experiment using a custom Annotation to repurpose Javadocs as a multiline String.

Copyright © 2023 Taeber Rapczak <taeber@rapczak.com>. License: MIT.

Quickstart

make

Protobuf Message Templates

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() {}
}

About

An experiment using a custom Annotation to repurpose Javadocs as a multiline String.

Topics

Resources

License

Stars

Watchers

Forks