The method emptyIntList() is undefined - protobuf-java

I am new to Google Protobuf. Tried to play with it using below student.proto file.
syntax = "proto3";
package rld;
option java_package = "com.rld";
option java_outer_classname = "StudentDTO";
message Student {
string name = 1;
int32 roll = 2;
repeated int32 mark = 3; //Marks in various subjects
}
message StudentDatabase {
repeated Student student = 1;
}
Then I tried to compile it using below Protobuf compiler command. From here, I downloaded the compiler.
protoc -I=. --java_out=. ./student.proto
It compiled successfully and generated StudentDTO.java, but with errors.
There are two methods 'emptyIntList()' and 'newIntList()' used inside the class, but they aren't defined.
Now my question is how to resolve those errors or am I missing something?

Being new, it seems I had forgotten to update Google Protobuf Runtime while updating Protobuf Compiler. Both the versions must match.
Here are 2 solutions.
Maven Users - Include the following dependency in your POM file.
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>x.y.z</version>
</dependency>
Non Maven Users - Include the protobuf-java-x.y.z.jar in your classpath.

Related

Jaxb generated sources with nullable fields

I have kotlin project where I'm using Jaxb generated src files from xsd. The problem with these generated sources is that they have nullable fields but IDEA does not know about it. It can lead to bugs in production. To fix it we can add #Nullable annotation to all getters in generated srs-es.
How can we do it gracefully?
I made this solution, it works for me but maybe somebody knows better approuch?
Gradle kt task
tasks.register("nullableForXsdFields") {
group = "code generation"
description = "Add Nullable annotation to generated jaxb files"
actions.add {
val xjcFiles = fileTree("$buildDir/generated-sources/main/xjc")
xjcFiles.forEach { xjcFile ->
var content = xjcFile.readText()
Regex("(public) (\\w+|<|>|\\*) (get)").findAll(content).distinct()
.forEach { match ->
content = content.replace(
match.groups[0]!!.value,
match.groups[0]!!.value.replace("public ", "public #Nullable ")
)
}.run {
content = content.replace(
"import javax.xml.bind.annotation.XmlType;",
"import javax.xml.bind.annotation.XmlType;\nimport org.jetbrains.annotations.Nullable;"
)
}
xjcFile.writeBytes(content.toByteArray())
}
}
}
tasks.getByName("xjcGeneration").finalizedBy("nullableForXsdFields")
tasks.getByName("compileKotlin").dependsOn("nullableForXsdFields")
tasks.getByName("compileJava").dependsOn("nullableForXsdFields")
xjcGeneration - is my plugin to generate src from xsd
I faced the same problem, so I've created an extension for maven jaxb plugin
com.github.labai:labai-jsr305-jaxb-plugin.
This extension marks all generated packages as nullable by default, and then marks with #NotNull only those fields, which are mandatory by xsd scheme.
You can find more details how to use it with maven in github
https://github.com/labai/labai-jsr305

Resolving a TypeReference to a TypeDefinition in Mono.Cecil fails with Assembly Resolution Error

I'm trying to get a Mono.Cecil TypeDefinition from a .NET type and not having any luck.
I'm using code like this:
var type = typeof(MarkdownMonster.AppConfiguration);
var a = AssemblyDefinition.ReadAssembly(type.Assembly.Location);
var tr = a.MainModule.Import(type); // this seems to work
var td = tr.Resolve(); // fails
but it fails with an assembly resolution error:
GetConfigurationPropertiesTest [0:29.990] Failed: Mono.Cecil.AssemblyResolutionException : Failed to resolve assembly: 'MarkdownMonster, Version=1.18.11.0, Culture=neutral, PublicKeyToken=null'
Mono.Cecil.AssemblyResolutionException : Failed to resolve assembly: 'MarkdownMonster, Version=1.18.11.0, Culture=neutral, PublicKeyToken=null'
at Mono.Cecil.BaseAssemblyResolver.Resolve(AssemblyNameReference name, ReaderParameters parameters)
at Mono.Cecil.DefaultAssemblyResolver.Resolve(AssemblyNameReference name)
at Mono.Cecil.MetadataResolver.Resolve(TypeReference type)
at Mono.Cecil.TypeReference.Resolve()
at Westwind.TypeImporter.TypeParser.ParseObject(Type type, Boolean dontParseMembers)
The assembly is obviously there, since the TypeReference import seems to work and produces a valid TypeReference.
The assembly in question is an EXE, and just for kicks I renamed it to a DLL but that had no effect.
After a bit of back and forth experimenting I found one (ugly) solution is to create a custom type resolver and basically forcing a hard type reference into it. It seems Mono.Cecil is able to resolve transient dependencies once it's found the main assembly, but not the top level reference.
To make this work I basically pass in the already resolved assembly reference. In my case I know the only reference I will need to return will be the top level reference so I hard code this. A more realistic example will have to use AssemblyDefinition.ReadAssembly() to read an assembly off disk or from a stream.
Here's is the code to create the AssemblyResolver:
public class MonoAssemblyResolver : IAssemblyResolver
{
public AssemblyDefinition AssemblyDefinition;
public AssemblyDefinition Resolve(AssemblyNameReference name)
{
return AssemblyDefinition;
}
public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
{
return AssemblyDefinition;
}
public void Dispose()
{
AssemblyDefinition = null;
}
}
Note the cheat to pass in an already resolved assembly reference.
To resolve I can now use the following code:
var a = AssemblyDefinition.ReadAssembly(type.Assembly.Location,
new ReaderParameters() { AssemblyResolver = resolver });
// assign the resolvedr
var resolver = new MonoAssemblyResolver();
resolver.AssemblyDefinition = a;
var tr = a.MainModule.Import(type: type);
var td = tr.Resolve(); // works now
This is crazy hacky, but can be adapted to be more generic (in my case not needed).
Still it would be much nicer if Mono.Cecil could automatically resolve the assembly - I don't understand why it's not finding the assembly in the first place since it lives in the current bin folder and the TypeReference can find it.
This is how it's normally done:
var assembly = #"c:\myassembly.dll";
var resolver = new DefaultAssemblyResolver();
// add .NET runtime dir for the sake of security
foreach (var dir in Directory.GetDirectories(RuntimeEnvironment.GetRuntimeDirectory(), "*", SearchOption.AllDirectories))
{
resolver.AddSearchDirectory(dir);
}
// add the assembly's directory
resolver.AddSearchDirectory(Path.GetDirectoryName(assembly));
var mod = AssemblyDefinition.ReadAssembly(assembly, new ReaderParameters { AssemblyResolver = resolver }).MainModule;
Regards

When overriding default configuration for Date Serialization, it becomes missing in the JSON example in metadata pages

I am attempting to override the default DateTime serialization with the following code:
JsConfig<DateTime>.SerializeFn = d =>
{
return d.ToString("o") + "Z";
};
JsConfig<DateTime>.RawSerializeFn = d =>
{
return d.ToString("o") + "Z";
};
(not sure the diff between SerializeFn and RawSerializeFn so i tried both to be sure...I also tried implementing the DeserializeFn in case they both needed to be overwritten, but saw some results)
Anyways... everytime I try this, any date members in our DTOs goes missing in the sample request/response JSON on the metadata pages. (date members still show in the Parameters section though).
I am using SS v4.0.40.0
PS: I later realized that my whole goal of appending "Z" to all DateTimes could be accomplished with this configuration:
JsConfig.DateHandler = DateHandler.ISO8601;
JsConfig.AssumeUtc = true;
JsConfig.AppendUtcOffset = false;
but I still wanted to file this bug - Thanks!
The DateTime serialization can't be changed in isolation, if you take over serializing to an unsupported custom format you'll also need to handle deserializing it with the appropriate RawDeserializeFn/DeserializeFn configuration.
You can also handle parsing unknown DateTime formats by registering a ParseError callback, i.e:
DateTimeSerializer.OnParseErrorFn = (dateTimeStr, ex) => //DateTime;
If you want to file an issue with any ServiceStack libraries, upgrade to the latest version of ServiceStack to ensure it's still an issue, if it is please submit it to github.com/ServiceStack/Issues with a sample code/failing test that reproduces the issue.

customized error reporting in v4

Another question on migrating code from v3 to v4:
For v3, I had a customized error reporting, using code like this (in the grammar file):
#members {
public void displayRecognitionError(String[] tokenNames,
RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
System.out.println("ERR:"+hdr+":"+msg);
errCount += 1;
}
}
In v4, when compiling the generated java files, I am getting the error:
MyParser.java:163: cannot find symbol
symbol : method getErrorMessage(org.antlr.v4.runtime.RecognitionException,java.lang.String[])
location: class MyParser
String msg = getErrorMessage(e, tokenNames);
^
Is this function replaced by some other function in v4? (I saw some questions and answers on ANTLRErrorListener, but I could not get how to use it for my situation.)
The displayRecognitionError method was removed in ANTLR 4, so even if you correct the body of that method it will not do anything. You need to remove the method from your grammar entirely, and implement ANTLRErrorListener instead. The documentation includes a list of classes that implement the interface, so you can reference those and/or extend one of them to produce the desired functionality.
Once you have an instance of an ANTLRErrorListener, you can use the following code to attach it to a Parser instance.
// remove the default error listener
parser.removeErrorListeners();
// add your custom error listener
parser.addErrorListener(listener);

Custom task build order in Gradle

I have a multi-project Gradle build with a custom defind xjc task to build the jaxb generated objects and I am having issues with steps building in the correct order.
I have 3 projects, common, ref and product. ref depends on common and product depends on ref and common. The naming is important to my problem as it seems gradle does things in alphabetical order and I have stripped out some other dependencies as they do not impact the problem.
Within each project the order should be jaxb, java compile and then scala compile.
In the top level build.gradle I specify the jaxb task to be:
task jaxb() {
description 'Converts xsds to classes'
def jaxbTargetFile = file( generatedSources )
def jaxbSourceFile = file ( jaxbSourceDir )
def jaxbEpisodesFile = file ( jaxbEpisodeDir )
def bindingRootDir = file ( rootDir.getPath() + '/')
inputs.dir jaxbSourceDir
outputs.dir jaxbTargetFile
doLast {
ant.taskdef(name: 'xjc', classname: 'com.sun.tools.xjc.XJCTask', classpath: configurations.jaxb.asPath)
jaxbTargetFile.mkdirs()
jaxbEpisodesFile.mkdirs()
for ( xsd in bindingsMap) {
if (!episodeMap.containsKey(xsd.key)) {
ant.fail( "Entry no found in the episodeMap for xsd $xsd.key" )
}
def episodeFile = projectDir.getPath() + '/' + jaxbEpisodeDir + '/' + episodeMap.get(xsd.key)
println( "Processing xsd $xsd.key with binding $xsd.value producing $episodeFile" )
ant.xjc(destdir: "$jaxbTargetFile", extension: true, removeOldOutput: true) {
schema(dir:"$jaxbSourceFile", includes: "$xsd.key")
binding(dir:"$bindingRootDir" , includes: "$xsd.value")
arg(value: '-npa')
arg(value: '-verbose')
arg(value: '-episode')
arg(value: episodeFile)
}
}
}
}
In the individual build.gradle file for product I specify (with similar in ref)
dependencies {
compile project(':common')
compile project(':ref')
}
and in all three projects I specify
compileJava.dependsOn(jaxb)
when I run publish (or jar) in the product project I can see the following output:
common:jaxb
common:compileJava
common:compileScala
common:jar
product:jaxb
ref:jaxb
refcompileJava
ref:compileScala
ref:jar
product:compileJava
product:compileScala
This gives me an error because the xsd in product refers to ref and as ref has not run jaxb yet there are no episode binding files for ref and product regenerates the imported classes with the wrong package name.
How can I ensure that ref jaxb runs before product jaxb?
If your product's jaxb tasks depends on jaxb tasks for ref and common, you should define this dependency:
(in product build.gradle)
task jaxb(dependsOn: [':common:jaxb', ':ref:jaxb']) {
...
}
Set same kind dependency in ref (on commmon)

Resources