Velocity template - retrieving hashmap values - velocity

I have a HashMap< String, List> which I fill inside the Java class. When I try to print it out in the Velocity template, it looks fine.
$!valuesMap ##gives {33=[texxxxt], 34=[2019-03-31], 35=[admin], 37=[P1], 40=[value1, value2]}
When I try to access the values directly, it also looks fine.
$!valuesMap.get("40") ##gives [value1, value2]
Problem arises when I try to use a dynamic variable to access the map. I have a list of objects over which I iterate, and each of these objects has an ID. However I cant figure out how to retrieve the value from the map using this ID.
#foreach( $field in $fields )
$!field.ID ##gives the id of the object, i.e. 40
##I would assume this would give me [value1, value2] when ID is 40, but it returns nothing
$!valuesMap.get($!field.ID)
#end
I have tried assigning the ID to a new variable (variable itself prints out fine, but again when I try to access the map, I get nothing). I have tried the notation suggested here and nothing ever prints out, it is honestly driving me up the wall, because I am probably missing something very simple, but cant figure out what it is.

Velocity Engine 1.7 does not convert method arguments towards expected types. So if $field.ID is a number, you have to enclose it in double quotes to get a string:
$valuesMap.get("$field.ID")
Otherwise, the engine simply doesn't find a proper method to call.
Starting with 2.0, Velocity Engine will automatically convert method arguments towards expected types, and your code will work as expected.

Related

ASSIGN fails with variable from debugger path

I am trying to assign the value of this stucture path to a fieldsymbol, but this path does not work because it has a table in it's path.
But with in the debugger this value of this path is shown correctly.
Is there a way to dynamically assign a component of a table line to a fieldsymbol, by passing one path?
If not then I will just read the table line and then use the path to get the wanted value.
ls_struct (Struct)
- SUPPLYCHAINTRADETRANSACTION (Struct)
- INCL_SUPP_CHAIN_ITEM (Table)
- ASSOCIATEDDOCUMENTLINEDOCUMENT (Element)
i_component_path = |IG_DDIC-SUPPLYCHAINTRADETRANSACTION-INCL_SUPP_CHAIN_ITEM[1]-ASSOCIATEDDOCUMENTLINEDOCUMENT|.
ASSIGN (i_component_path) TO FIELD-SYMBOL(<lg_value>).
IF <lg_value> IS NOT ASSIGNED.
return.
ENDIF.
<lg_value> won't be assigned
Solution by Sandra Rossi
The debugger has its own syntax and own logic, it doesn't apply the ASSIGN algorithm at all. With ABAP source code, you have to use ASSIGN twice, the first one to reach the internal table, then you select the first line, and the second one to reach the component of the line.
The debugger works completely differently, the debugger code works only in debug mode, you can't call the code from the debugger (i.e. if you call it, the kernel code used by the debugger will fail). No, there's no "abappath". There are the XSL transformation objects (xpath), but it's slow for what you ask.
Thank you very much
This seems to be a rather unexpected limitation of the ASSIGN statement. Probably worth a ticket to SAP's ABAP language group to clarify whether it's even a bug.
While this works:
ASSIGN data-some_table[ 1 ]-some_field TO FIELD-SYMBOL(<lv_source>).
the same expressed as a string doesn't:
ASSIGN (`data-some_table[ 1 ]-some_field`) TO FIELD-SYMBOL(<lv_source>).
Alternative 1 for (name) of the ABAP keyword documentation for the ASSIGN statement says that "[t]he name in name is structured in the same way as if specified directly".
However, this declaration is immediately followed by "the content of name must be the name of a data object which may contain offsets and lengths, structure component selectors, and component selectors for assigning structured data objects and attributes in classes or objects", a list that does not include the table expressions we would need here.

VB.net String Reverse Property different based on Env

I am debugging an application that runs on a server and users will access the application on another server. The application uses encryption and as part of the key, I am using the String.Reverse property.
Dim Mystring As String = "123abc"
Dim reverse = String.Format("{0},{1}", Mystring.Reverse)
The string reverse is different when I run it from one machine (RDP/Citrix Environment ASP.NET 4.6.1). The value is:
System.Linq.Enumerable+<ReverseIterator>d__a2`1[System.Char]
The same string, but ran from another machine (RPD non-Citrix Environment ASP.NET 4.5.2). The value of reverse is:
System.Linq.Enumerable+<ReverseIterator>d__73`1[System.Char]
Why are the values different in the different environments?
Look at this line first:
Dim reverse = String.Format("{0},{1}", Mystring.Reverse)
Specifically, this expression:
Mystring.Reverse
Reverse is a function, not a property, but it's missing the parentheses (). The trick here is the String.Format() method accepts the base Object type as an argument, and compiler is able to treat the MyString.Reverse expression as a delegate type that is convertible to object. The values you see in your output are the result of calling .ToString() on that function delegate. It's the type name for the function, rather than anything to do with the value of your MyString object. Since that type is dynamically and randomly generated at runtime, you'll see different values not only on different platforms, but different runs on the same computer.
In the VB6 era, it was normal to call methods without the parentheses. In the .Net world, always use parentheses when you call a method.
What you want is this:
Dim reverse As String = String.Format("{0},{1}", Mystring.Reverse())
Even here, you're missing the second argument to match the format string. I doubt you'll get the result you expect.
Finally, reversing a string as the key seems very wrong when it comes to encryption. You are using a real cyrptogrpahic algorithm from the System.Security.Cryptography library, right? Right!?
You are not outputting the value of the reversed String but the name of the type used to perform the reversal. That type is dynamically created and randomly named. The "d" in those two names means "dynamic" and the "a2" and "73" parts are random.
Basically, what you perceive to be an issue is not an issue. The problem is that you're not actually creating a String from the reversed output. You say "String.Reverse property but that is NOT a property. It is a method and it is not a member of the String class but rather an extension method on the IEnumerable(Of T) interface. You are treating your String as an enumerable list of Char values and reversing that. If you want a String from that then you need to create one, i.e.
MyReversedString = New String(Mystring.Reverse().ToArray())
That will push the contents of your iterator into an array and then create a new String object from that array.

Proper error propagation in clojure

I'm currently working on my first major project in clojure and have run into a question regarding coding style and the most "clojure-esque" way of doing something. Basically I have a function I'm writing which takes in a data structure and a template that the function will try to massage the data structure into. The template structure will look something like this:
{
:key1 (:string (:opt :param))
:key2 (:int (:opt :param))
:key3 (:obj (:tpl :template-structure))
:key4 (:list (:tpl :template-structure))
}
Each key is an atom that will be searched for in the given data structure, and it's value will be attempted to be matched to the type given in the template structure. So it would look for :key1 and check that it's a string, for instance. The return value would be a map that has :key1 pointing to the value from the given data structure (the function could potentially change the value depending on the options given).
In the case of :obj it takes in another template structure, and recursively calls itself on that value and the template structure, and places the result from that in the return. However, if there's an error I want that error returned directly.
Similarly for lists I want it to basically do a map of the function again, except in the case of an error which I want returned directly.
My question is what is the best way to handle these errors? Some simple exception handling would be the easiest way, but I feel that it's not the most functional way. I could try and babysit the errors all the way up the chain with tons of if statements, but that also doesn't seem very sporting. Is there something simple I'm missing or is this just an ugly problem?
You might be interested in schematic, which does pretty similar stuff. You can see how it's used in the tests, and the implementation.
Basically I defined an error function, which returns nil for correctly-formatted data, or a string describing the error. Doing it with exceptions instead would make the plumbing easier, but would make it harder to get the detailed error messages like "[person: [first_name: expected string, got integer]]".

How to use the data store to set a toolbar title in Sencha Touch

I am trying to set the toolbar item dynamically. So far I have a back button that resets the toolbar title to 'start' if the user chooses to go back.
But the following code won't work:
menuList.on('itemtap', function(dataView, index, item, e){
viewport.dockedItems.items[0].setTitle('{title}');
});
It tries to use a variable called 'title' out of my data store array. This works great for providing text to my Ext.List items. But the above code sets the toolbar title to the string '{title}' without even thinking of it being a variable.
Can you help me out?
List's use templates so items within curley braces get evaluated... you'll need to pass a reference to a variable without quotes. You haven't provided enough code for me to tell you where that information would be. If you already have a variable in scope called title that you put the data into then you can just reamove the '{ and }' ... otherwise you'll need to get the data you need from your store through some means, like Ext.StoreMgr or [appname].stores
Two things. 1) You will really want to get used to digging into the ST source code. In this case, if you look at the code for "setTitle", you will see that its argument is interpreted as straight HTML, not a template. So you can't use curly bracket syntax here. 2) Note that the type of the "item" argument to the event handler is an Element (i.e. ST's representation of the DOM object, not the selected datastore object. So that's not going to help you. However, the "index" arg gives you an easy way to get the appropriate object from the store. i.e.
[appname].stores.pages.getAt(index).title
I really don't know why, but it works if you put up to variables: One for the record and one for the value inside that record. There is a detailed explanation in the sencha.com-forum

Lambdas with captured variables

Consider the following line of code:
private void DoThis() {
int i = 5;
var repo = new ReportsRepository<RptCriteriaHint>();
// This does NOT work
var query1 = repo.Find(x => x.CriteriaTypeID == i).ToList<RptCriteriaHint>();
// This DOES work
var query1 = repo.Find(x => x.CriteriaTypeID == 5).ToList<RptCriteriaHint>();
}
So when I hardwire an actual number into the lambda function, it works fine. When I use a captured variable into the expression it comes back with the following error:
No mapping exists from object type
ReportBuilder.Reporter+<>c__DisplayClass0
to a known managed provider native
type.
Why? How can I fix it?
Technically, the correct way to fix this is for the framework that is accepting the expression tree from your lambda to evaluate the i reference; in other words, it's a LINQ framework limitation for some specific framework. What it is currently trying to do is interpret the i as a member access on some type known to it (the provider) from the database. Because of the way lambda variable capture works, the i local variable is actually a field on a hidden class, the one with the funny name, that the provider doesn't recognize.
So, it's a framework problem.
If you really must get by, you could construct the expression manually, like this:
ParameterExpression x = Expression.Parameter(typeof(RptCriteriaHint), "x");
var query = repo.Find(
Expression.Lambda<Func<RptCriteriaHint,bool>>(
Expression.Equal(
Expression.MakeMemberAccess(
x,
typeof(RptCriteriaHint).GetProperty("CriteriaTypeID")),
Expression.Constant(i)),
x)).ToList();
... but that's just masochism.
Your comment on this entry prompts me to explain further.
Lambdas are convertible into one of two types: a delegate with the correct signature, or an Expression<TDelegate> of the correct signature. LINQ to external databases (as opposed to any kind of in-memory query) works using the second kind of conversion.
The compiler converts lambda expressions into expression trees, roughly speaking, by:
The syntax tree is parsed by the compiler - this happens for all code.
The syntax tree is rewritten after taking into account variable capture. Capturing variables is just like in a normal delegate or lambda - so display classes get created, and captured locals get moved into them (this is the same behaviour as variable capture in C# 2.0 anonymous delegates).
The new syntax tree is converted into a series of calls to the Expression class so that, at runtime, an object tree is created that faithfully represents the parsed text.
LINQ to external data sources is supposed to take this expression tree and interpret it for its semantic content, and interpret symbolic expressions inside the tree as either referring to things specific to its context (e.g. columns in the DB), or immediate values to convert. Usually, System.Reflection is used to look for framework-specific attributes to guide this conversion.
However, it looks like SubSonic is not properly treating symbolic references that it cannot find domain-specific correspondences for; rather than evaluating the symbolic references, it's just punting. Thus, it's a SubSonic problem.