I am trying to set a flag so I do something like this:
<set field="existingFound" value="false" type="Boolean"/>
but the following line prints "true" in the log:
<log message="storeProperty, existingFound (0): ${existingFound}"/>
What is the best way to set flags?
The set.#value attribute is interpreted as a Groovy String (GString) so any non-empty value will be interpreted as true. The set.#from attribute is interpreted as a Groovy expression, so simply using from="false" instead of value="false" will get the desired result.
To see the generated Groovy code from an XML actions block you can write code that will cause an error and then the script will be logged, or you can change the log4j.xml file to turn on "debug" level logging for the XmlActions class (the latest log4j.xml file in the GitHub repository has an example of this). Looking at the Groovy code generated from the XML elements is a good way to track down issues when what is happening just doesn't make sense.
Related
So in my targets file, I've got a line that looks like this:
<XmlPeek Namespaces="" XmlInputPath="file.xml" Query="/data/#AttributeOne">
<Output TaskParameter="Result" ItemName="my_AttributeOne" />
</XmlPeek>
in "file.xml", I have:
<data AttributeOne="abc" AttributeTwo="def" />
it also reads a few other attributes.
When the attribute has data, everything works fine... but when I leave AttributeOne as an empty string (""), XmlPeek blows chunks with the following error:
The "XmlPeek" task's outputs could not be retrieved from the "Result" parameter. Parameter "includeEscaped" cannot have zero length.
if I remove the attribute ENTIRELY, it works fine (the resulting item is obviously and understandably blank)
The question is... how can I DETERMINE, WITHOUT blowing chunks, the value of a blank attribute... whether by pre-testing for a value, or by correctly handling the blank, or some other means.
CONSTRAINT: the only real requirement is to stick to the built-in tasks (XmlPeek)... I'm aware of XmlRead in the community tasks... for various reasons, I want to use out-of-the-box tasks.
Thanks in advance!
The error happens because an empty string is being used as the Item Identifier. I guess identifiers cannot be the empty string. If you remove the attribute then the result is null and no Item is created so that's why that doesn't throw an error.
Maybe try return the result as a Property instead of an Item.
If you do not need to distinguish between the attribute being omitted versus having an empty value, you can prevent the error by inserting the condition [#AttributeOne!=''] into the query as follows.
<XmlPeek Namespaces="" XmlInputPath="file.xml" Query="/data[#AttributeOne!='']/#AttributeOne">
<Output TaskParameter="Result" ItemName="my_AttributeOne" />
</XmlPeek>
The intention in the title sounds more complex as it is
I have a script which looks like that:
<Import Project="MSBuild/Backend.msbuild.xml" />
<PropertyGroup>
<Data>SomeData</Data>
</PropertyGroup>
and I simply want to detect whether the Import statement is before or after the PropertyGroup because the Backend script looks like
<PropertyGroup>
<BasedOnData>$(Data)/magic.exe</BasedOnData>
</PropertyGroup>
If the Import statement comes first, BasedOnData just looks like /magic.exe which is wrong. If the Import comes last, everything is fine.
I tried to check the Data Property in a Target in Backend but at target-calling-time Data is already defined.
Resulting in
Data=SomeData
but
BasedOnData=/magic.exe
I could create an Error condition based whether $(BasedOnData)== '/magic.exe' but this is error prone as it relies on Data and BasedOnDatas value.
Having an Error condition in PropertyGroup does not work.
Any smarter solution to this known?
Should I fallback to CreateProperty in the first target so I am agnostic of the position of the Import statement? (This gets much more verbose and is not that easy to read than a plain nice PropertyGroup.)
Execution of MSBuild targets happens in separate pass, after all properties in property groups have been evaluated. So what you are observing is designed behavior.
To make import order checking in your case, the following should do the trick. Inside your Backend.msbuild.xml file add this:
<PropertyGroup>
<Data_Copy>$(Data)</Data_Copy>
</PropertyGroup>
This just makes a copy of whatever $(Data) value was at the time. Then in either same imported file or in any other target, add this <Error> task:
<Error Text="Import has to be specified after `Data` is defined" Condition="'$(Data_Copy)' == ''" />
This will break the build if Backend.msbuild.xml was imported before $(Data) is defined.
One of my goals in creating the bootstrap project is to set a default log location. I would like the location to be based on the local app data folder. I cannot figure out how to reference the builtin Burn variable LocalAppDataFolder. I have found information about how to reference these variables in code, but not in the xml.
The reference to the property looks like this:
<MsiPackage SourceFile="MyInstaller.msi" LogPathVariable="[LogLocation]" />
The property is set like this:
<Variable Name="LogLocation" Value="[LocalAppDataFolder]MyLogFolder\Setup" Type="string"/>
The log output shows:
Initializing string variable 'LogLocation' to value
'[LocalAppDataFolder]MyLogFolder\Setup'
What am I missing to resolve [LocalAppDataFolder] ?
thanks in advance.
It's normal for the log output to show the un-formatted value, so that part looks correct. I think what you are missing is LogPathVariable should be specified without the brackets.
<MsiPackage SourceFile="MyInstaller.msi" LogPathVariable="LogLocation" />
After following the struts 2 web pages and numerous examples, my application still will not pick up values from the struts.properties file.
I am trying this in order to give some values a money type format:
<s:property value="getText('struts.money.format',{value})" />
My struts.properties file which is under WEB-INF/classes and therefore visible has the following single line
struts.money.format= {0,number,\u00A4##0.00}
I get the string struts.money.format printed to the screen. If I change the first parameter of the getText call, the new string I put also will get printed instead of a true lookup happening.
If I do <s:property value="value" /> I will get back a proper number. If I drop the second argument on the getText call, I would expect to get back the right hand side of the assignment in the properties file, but i get the same struts.money.format back.
I am using Tomcat 6 with Struts 2.2.1.1. Is there an additional part of the puzzle I am possibly leaving out?
So in my struts.xml file, I put this line
<constant name="struts.custom.i18n.resources" value="struts" />
It needs this to know that I am trying to use a struts.properties file. I had assumed that by default a file named struts.properties was along the chain of places to look for a constant such as this. Only if you named it something else did you need to specify that. Even though it is in WEB-INF/classes which is recommended by the Struts 2 documentation, it just simply was not looking in this file.
EDIT
For what it is worth, I also had to modify my struts text tag like so
<s:property value="getText('struts.money.format',{#java.lang.Double#valueOf(value)})" />
Actually, value should have been a BigDecimal, but it was being treated at the view level here as java.lang.String. The problem is that some of the String objects had exponential formatting (like 1.642E07 or something to that effect) and the struts formatter could not handle the exponential formatting. The valueOf eliminates this exponential fomatting
I'm using the json plugin that comes with struts 2 (json-lib-2.1.jar) and trying to follow the website to set it up.
Here's my struts.xml
<struts>
<package name="example" extends="json-default">
<action name="AjaxRetrieveUser" class="actions.view.RetrieveUser">
<result type="json"/>
</action>
</package>
</struts>
but I get this warning:
SEVERE: Unable to find parent packages json-default
Is there something else I'm supposed to do?
Edit:
I added this method to my RetrieveUser:
public Map<String,Object> getJsonModel()
{
return jsonModel;
}
And my struts.xml looks like this:
<struts>
<package name="example" extends="json-default">
<action name="AjaxRetrieveUser" class="actions.view.RetrieveUser">
<result type="json"/>
<param name="root">jsonModel</param>
</action>
</package>
</struts>
However, I don't think the response is going from the RetrieveUser class to the javascript. I'm using firebug and no request gets sent.
I believe that net.sf.json-lib is just a toolset you can use in your Java to build up JSON-ready objects, suitable to be returned by actions such as you describe.
Probably, you need to include struts-json-plugin - make sure its version matches your struts version.
I notice also that as written, your action will attempt to return RetrieveUser, serialized. Most implementations I've done/seen specify the root object to be returned, by adding
<param name="root">jsonUser</param>
Under the tag, and define this method in RetrieveUser
public Map<String, Object> getJsonUser()
[This is mentioned in the Sruts2 doc]. Hope that helps.
[edit] I use Map - you could also use the object structures provided by json-lib instead.
Re: Your edit. Probably need to see your calling javascript. And probably I will suggest that you make sure you have both a success and an error handler. Can you debug/log to show that the method is being called in java ? Do your logs show anything ? This is usually some sort of error....