How to get rid of StringTemplate warning "\n in string" - stringtemplate

I'm using StringTemplate 4 to generate some Java source files.
The templates are really simple, e.g.:
QueryHandler(method) ::="
public class Obtenir<method.name>Handler extends QueryHandler\<List\<<method.name>Db>> implements IQueryHandler\<List\<<method.name>>>{
private IQuery\<List\<<method.name>Db>> query;
private <method.name>Converter converter;
#Inject
public Obtenir<method.name>Handler(IQuery\<List\<<method.name>Db>> query, <method.name>Converter converter, IStatisticsCollecter theStatsCollecter){
super(theStatsCollecter);
if(query == null){
throw new IllegalArgumentException(\"The query argument cannot be null\");
}
if(converter == null){
throw new IllegalArgumentException(\"Illegal argument for converter(null)\");
}
this.query = query;
this.converter = converter;
}
public List\<<method.name>> handle(Object... params) throws JdbcException {
final String method = \"obtenir<method.name>\";
DaoQueryStatusCallable status = new DaoQueryStatusCallable();
List\<<method.name>Db> result = invoke(query, status, method);
return converter.convert(result);
}
}
"
The code is even simpler:
STGroup group = new STGroupFile("src/main/resources/QueryHandler.stg");
ST wsTemplate = group.getInstanceOf("QueryHandler");
wsTemplate.add("method", m);
System.out.println(wsTemplate.render());
The template lines are separated by Unix EOLs (\n).
When I execute the code, StringTemplate is emitting a warning "QueryHandler.stg 1:25: \n in string".
The result is correct, but I'd still like to get rid of this message.
Anybody ever had this problem and knows how to solve it?

t() ::= "..." is meant only for single lines. Please use
t() ::= <<
...
>>
to get multi-line templates.
Ter

Related

Trying to do a structural replace in IntelliJ

I want to replace my annotations from #RequestMapping to #GetMapping, #PutMapping ... annotations. When I looked at the Structural Find/Replace in IntelliJ looked like it could do the job.
I tried adding the following in the search
#RequestMapping( $key$ = $value$)
Added a filter on the key. text=method.
Now I want to extract the from the value (RequestMethod.GET) , the word after . (period). and then in the replacement add
#[Word(TitleCase)]Mapping( [everything except the key,value that was extracted in the search])
Haven't been able to figure out how to go about this. Would be nice to know if this can't be done, or any suggestions on how to do this. Looked at some of the other questions here on SO, but didn't find anything that could help. Most of the answers are to use regex in those cases.
Before:
#RequestMapping(
value = "/channels/{channel_name}",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
public Channel updateChannel(
#PathVariable("channel_name") String channelName,
#Valid #RequestBody Channel channel) {
return channelService.updateChannel(channelName, channel);
}
#RequestMapping(
value = "/channels/{channel_name}",
method = RequestMethod.DELETE,
produces = MediaType.APPLICATION_JSON_VALUE)
public Channel deleteChannel(
#PathVariable("channel_name") String channelName) {
return channelService.deleteChannel(channelName);
}
After
#PostMapping(value = "/channels/{channel_name}",
produces = MediaType.APPLICATION_JSON_VALUE,
consumes = MediaType.APPLICATION_JSON_VALUE)
public Channel updateChannel(
#PathVariable("channel_name") String channelName,
#Valid #RequestBody Channel channel) {
return channelService.updateChannel(channelName, channel);
}
#DeleteMapping(
value = "/channels/{channel_name}",
produces = MediaType.APPLICATION_JSON_VALUE)
public Channel deleteChannel(
#PathVariable("channel_name") String channelName) {
return channelService.deleteChannel(channelName);
}
I would do this dirty, with regex:
Replace RequestMethod.(.)(.+)(?=,) into RequestMethod.\U$1\L$2 (\L would turn the text into lowercase.)
Replace #RequestMapping\((\s+)(.+)(\s+?)(.+)RequestMethod.(.+?), into #$5Mapping\($1$2$3.
Then simplify this replacement chain:
Replace #RequestMapping\((\s+)(.+)(\s+?)(.+)RequestMethod.(\S)(.+?), into #\U$5\L$6\EMapping\($1$2
Update: Noticed the first parameter value is not specified whether in the line of #Mapping or a standalone line.
If you need it in the line of #Mapping, replace #RequestMapping\((\s+)(.+)(\s+?)(.+)RequestMethod.(\S)(.+?),\s into #\U$5\L$6\EMapping\($2$3.
If you need it to a standalone line, replace #RequestMapping\((\s+)(.+)(\s+?)(.+)RequestMethod.(\S)(.+?), into #\U$5\L$6\EMapping\($1$2.

Data is written to BigQuery but not in proper format

I'm writing data to BigQuery and successfully gets written there. But I'm concerned with the format in which it is getting written.
Below is the format in which the data is shown when I execute any query in BigQuery :
Check the first row, the value of SalesComponent is CPS_H but its showing 'BeamRecord [dataValues=[CPS_H' and In the ModelIteration the value is ended with a square braket.
Below is the code that is used to push data to BigQuery from BeamSql:
TableSchema tableSchema = new TableSchema().setFields(ImmutableList.of(
new TableFieldSchema().setName("SalesComponent").setType("STRING").setMode("REQUIRED"),
new TableFieldSchema().setName("DuetoValue").setType("STRING").setMode("REQUIRED"),
new TableFieldSchema().setName("ModelIteration").setType("STRING").setMode("REQUIRED")
));
TableReference tableSpec = BigQueryHelpers.parseTableSpec("beta-194409:data_id1.tables_test");
System.out.println("Start Bigquery");
final_out.apply(MapElements.into(TypeDescriptor.of(TableRow.class)).via(
(MyOutputClass elem) -> new TableRow().set("SalesComponent", elem.SalesComponent).set("DuetoValue", elem.DuetoValue).set("ModelIteration", elem.ModelIteration)))
.apply(BigQueryIO.writeTableRows()
.to(tableSpec)
.withSchema(tableSchema)
.withCreateDisposition(CreateDisposition.CREATE_IF_NEEDED)
.withWriteDisposition(WriteDisposition.WRITE_TRUNCATE));
p.run().waitUntilFinish();
EDIT
I have transformed BeamRecord into MyOutputClass type using below code and this also doesn't work:
PCollection<MyOutputClass> final_out = join_query.apply(ParDo.of(new DoFn<BeamRecord, MyOutputClass>() {
private static final long serialVersionUID = 1L;
#ProcessElement
public void processElement(ProcessContext c) {
BeamRecord record = c.element();
String[] strArr = record.toString().split(",");
MyOutputClass moc = new MyOutputClass();
moc.setSalesComponent(strArr[0]);
moc.setDuetoValue(strArr[1]);
moc.setModelIteration(strArr[2]);
c.output(moc);
}
}));
It looks like your MyOutputClass is constructed incorrectly (with incorrect values). If you look at it, BigQueryIO is able to create rows with correct fields just fine. But those fields have wrong values. Which means that when you call .set("SalesComponent", elem.SalesComponent) you already have incorrect data in the elem.
My guess is the problem is in some previous step, when you convert from BeamRecord to MyOutputClass. You would get a result similar to what you're seeing if you did something like this (or some other conversion logic did this for you behind the scenes):
convert BeamRecord to string by calling beamRecord.toString();
if you look at BeamRecord.toString() implementation you can see that you're getting exactly that string format;
split this string by , getting an array of strings;
construct MyOutputClass from that array;
Pseudocode for this is something like:
PCollection<MyOutputClass> final_out =
beamRecords
.apply(
ParDo.of(new DoFn() {
#ProcessElement
void processElement(Context c) {
BeamRecord record = c.elem();
String[] fields = record.toString().split(",");
MyOutputClass elem = new MyOutputClass();
elem.SalesComponent = fields[0];
elem.DuetoValue = fields[1];
...
c.output(elem);
}
})
);
Correct way of doing something like this is to call getters on the record instead of splitting its string representation, along these lines (pseudocode):
PCollection<MyOutputClass> final_out =
beamRecords
.apply(
ParDo.of(new DoFn() {
#ProcessElement
void processElement(Context c) {
BeamRecord record = c.elem();
MyOutputClass elem = new MyOutputClass();
//get field value by name
elem.SalesComponent = record.getString("CPS_H...");
// get another field value by name
elem.DuetoValue = record.getInteger("...");
...
c.output(elem);
}
})
);
You can verify something like this by adding a simple ParDo where you either put a breakpoint and look at the elements in the debugger, or output the elements somewhere else (e.g. console).
I was able to resolve this issue using below methods :
PCollection<MyOutputClass> final_out = record40.apply(ParDo.of(new DoFn<BeamRecord, MyOutputClass>() {
private static final long serialVersionUID = 1L;
#ProcessElement
public void processElement(ProcessContext c) throws ParseException {
BeamRecord record = c.element();
String strArr = record.toString();
String strArr1 = strArr.substring(24);
String xyz = strArr1.replace("]","");
String[] strArr2 = xyz.split(",");

Referencing a global variable in forloop from Apache Velocity

I am having trouble with having a formatter within a forloop in Apache Velocity.
#set( $array = ["10000", "3000", "13.456", "1111.13"] )
<ul>
#foreach( $a in $array)
<li>$formatter.print($a)</li>
#end
</ul>
This would be evaluated and print the original expression as a string 4 times
$formatter.print($a)
$formatter.print($a)
$formatter.print($a)
$formatter.print($a)
instead of
10,000.00
3,000.00
13.456
1,111.13
However it seems to work fine with the formatter outside of the scope from the forloop
<p>$formatter.print(123456)</p>
This would work as usual
Can anyone helps me figuring out how to reference a property (in this case $formatter) within a for loop ?
This can happen when one of the following condition is true:
1) The model passed to the velocity does not have the variable "formatter"
2) The method print is returning null or it does not exist
3) The method print accepts a parameter of the wrong type. Try to pass Object...
The following code works for me (notice that I am using an array of double and not any more an array of string):
package test;
import java.io.StringWriter;
import org.apache.velocity.app.VelocityEngine;
import org.apache.velocity.runtime.RuntimeConstants;
import org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
public class VelocityHelloWorld
{
public static void main( String[] args )
throws Exception
{
VelocityEngine ve = new VelocityEngine();
ve.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());
ve.init();
VelocityContext context = new VelocityContext();
context.put("formatter", new Formatter());
Template t = ve.getTemplate( "helloworld.vm" );
StringWriter writer = new StringWriter();
t.merge( context, writer );
System.out.println(writer.toString());
}
}
Velocity:
#set( $array = [10.00 , 20.00, 13.456, 1111.13] )
<ul>
#foreach( $a in $array)
<li>$formatter.print($a)</li>
#end
</ul>
Formatter:
package test;
public class Formatter {
public String print (Object d) {
String s = d.getClass().getName() + ": " + d.toString();
return s;
}
}
The template shows the same behaviour like yours if I substitute in
print (Double d)
Double with Float.
Long story short... I think that you probably need to check the parameter passed to your method.
Of course I think you should use Double and create the array as a list of double and not as a list of strings.
Try ${myref.doIt($var)} syntax to reference context variable. This ensures Velocity does not parse context names incorrectly within strings.

NHibernate HQL Generator Caching Expression

I have created the following NHibernate HQL generator:
public class ContainsGenerator : BaseHqlGeneratorForMethod {
public ContainsGenerator() {
SupportedMethods = new[] {
ReflectionHelper.GetMethodDefinition(() =>
MyExtensions.Contains(null, null))
};
}
public override HqlTreeNode BuildHql(MethodInfo method, Expression targetObject,
ReadOnlyCollection<Expression> arguments, HqlTreeBuilder treeBuilder,
IHqlExpressionVisitor visitor) {
var exp = FormatExpression((string)((ConstantExpression)arguments[1]).Value);
return treeBuilder.BooleanMethodCall("CONTAINS", new[] {
visitor.Visit(arguments[0]).AsExpression(),
treeBuilder.Constant(exp)
});
}
private string FormatExpression(string exp) {
exp = exp.Replace("'", "''");
exp = exp.Replace("\"", "");
exp = (char)34 + Regex.Replace(exp,
"(AND NOT|AND|OR NOT|OR) ",
(char)34 + " $1 " + (char)34, RegexOptions.IgnoreCase)
+ (char)34;
return exp;
}
}
This is used to do Full-Text searching to speed up searching over large tables.
The only difference to this and previous generators I've built in the past is that I call FormatExpression to convert the search expression to the correct format that SQL Server understands. However this seems to be the problem because although it works the first time I fire the query, subsequent searches produces the same query and the second argument passed into CONTAINS never changes. For example If I say:
var products = session.Query<Product>().Where(p => p.Name.Contains("Test 1")).ToList();
It will produce the following query:
select product0_.Id as Id2_,
product0_.Name as Name2_, from [dbo].Products product0_ where CONTAINS(product0_.Name, '"Test 1"')
Now if I say:
var products = session.Query<Product>().Where(p => p.Name.Contains("Test 2")).ToList();
It produces exactly the same query.
I'd appreciate it if someone could show me the correct way to do this. Thanks
It is a known bug in NHibernate: see https://nhibernate.jira.com/browse/NH-2658.

getting user defined error messages using antlr3

numberrange returns [String value]
: numberrangesub
{
String numberRange = ($numberrangesub.text);
String [] v = numberRange.split(",");
if ( Integer.parseInt(v[0].trim()) < Integer.parseInt(v[1].trim())) $value =numberRange;
else throw new RecognitionException();
}
;
Please observe the above ANTLR code. In this I want to throw a user friendly error message like "from value should be less than to value in BETWEEN clause".
I am expecting like this RecognitionException("from value should be less than to value in BETWEEN clause"); But antlr did not accept like as above.
In java class where I am calling the generated java class by Antlr. I am handling like as follows.
try
{
parser.numberRangeCheck();
}
catch (RecognitionException e)
{
throw createException("Invalid Business logic syntax at " + parser.getErrorHeader(e) + ", " + parser.getErrorMessage(e, null), Level.INFO, logger);
}
Any help will be appriciated.
Why not simply throw a RuntimeException with your custom error message?
// ...
else throw new RuntimeException("from value should be less than to value in BETWEEN clause");
// ...
As Terrance wrote in "The Definitive ANTLR Reference" error chapter excerpt:
To avoid forcing English-only error messages and to generally make
things as flexible as possible, the recognizer does not create exception
objects with string messages. Instead, it tracks the information necessary to generate an error.
So there is no error message supplied to RecognitionError's constructor. But you can define additional field of your recognizer to hold user-friendly error message shown on RecognitionError handling:
numberrange returns [String value]
: numberrangesub
{
String numberRange = ($numberrangesub.text);
String [] v = numberRange.split(",");
if ( Integer.parseInt(v[0].trim()) < Integer.parseInt(v[1].trim()))
$value = numberRange;
else {
this.errorMessage = "from value should be less than to value in BETWEEN clause";
throw new RecognitionException(this.input);
}
}
;
And then override the getErrorMessage method:
public String getErrorMessage(RecognitionException e, String[] tokenNames) {
String msg = this.errorMessage;
// ...
}
This works similar to paraphrase mechanism explained in the same excerpt.