My Xpages app has a cacheBean for application wide settings. I have a managed Bean for a PC document, which has field status of type integer.
In the cacheBean I have a method getPCStatus(Integer status) that when given the number will return the string text of the status.
On my Xpage I have a text field which I want to bind to the result of
cacheBean.getPCStatus(PCBean.status)
so it will return "In Inventory" for a 1 and something else for a 2 etc.
However, the code is throwing an error.
Here is the code:
readonly="true">
<xp:this.value><![CDATA[#{CacheBean.getPCStatus(PCModelBean.status)}]]></xp:this.value>
</xp:inputText>
The error is
Error in EL syntax, property 'value': CacheBean.getPCStatus(PCModelBean.status)
I know I read something about this long ago but cannot remember how to handle this, but cannot find it.
I was wondering if the method getPCStatus should be in the PCBean or in the cacheBean?
The version of EL used n XPages doesn't have support for calling methods with parameters. If getPCStatus() were a zero-argument method, you could call it with #{CacheBean.pCStatus}, presumably, but as it is it's the parameter that's in your way.
There are a few common workarounds: if CacheBean itself implements Map or DataObject, then EL will call the get or getValue method, respectively, with whatever you put after the "." - you could use that to sort of fake method calls.
Alternatively, you could keep CacheBean a POJO (not implementing one of those interfaces) but have the return value from getPCStatus itself be a Map or DataObject, which would take whatever value you pass in (in this case, PCModelBean.status) and do the lookup, with a binding like #{CacheBean.pCStatus[PCModelBean.status]}. DataObjects aren't too bad to write: https://frostillic.us/blog/posts/FE0AE00B7CEC4F8885257D46006CAB68
Or, as an complete alternative to all of this, if you don't need your binding to be read+write, you could use SSJS to call the method.
Related
i have a question. I would like to call a static java method Integer.toHexString() in a freemaker template.
In my code i implemented following lines:
....
cfg.setSharedVariable("Integer",BeansWrapper.getDefaultInstance().
getStaticModels().
get("java.lang.Integer");
....
);
My template looks like this
<#list Items.iterator() as var>
<#assign hex = Integer.toHexString(var) />
${hex}
</#list>
But if i execute the code i get following error:
freemarker.core._TemplateModelException: An error has occurred when reading existing sub-variable "Integer"; see cause exception! The type of the containing value was: extended_hash+string (org.json.JSONObject wrapped into f.e.b.StringModel)
----
FTL stack trace ("~" means nesting-related):
- Failed at: #assign hex = Integer.toHexString(var... [in template "decToHex.ftl"...]
What am i doing wrong?
Thanks.
Based on the error message, your data-model (aka. template context) is a org.json.JSONObject. FreeMarker doesn't know that API, but it discovers that JSONObject has a get(String) method, and tries to use that. Unfortunately, that get method doesn't behave as a Map-style get(key). FreeMarker first calls JSONObject.get("Integer") to see if the variable is in the data-model. If it isn't, it expects a null to be returned, and then will try to get it from higher scopes (like from the shared variables). But JSONObject.get(String) throws JSONException instead of returning null, which is what you see in the error log (if you look at the whole stack trace, JSONException should be there as the cause exception).
To solve this, you need teach FreeMarker how to deal with JSONObject-s:
Create a class, let's call it JSONObjectAdapter, which implements TemplateHashModelEx2 (or, the much simpler TemplateHashModel can be enough for basic use-cases). Inside that, when implementing TemplateHashModel.get(String), you must call JSONObject.has(key) to check if the key exists, and if not, return null, otherwise continue with calling JSONObject.get(key).
Create a class, let's call it DefaultObjectWrapperWithJSONSupport, that extends DefaultObjectWrapper. Your class should wrap JSONObject-s with JSONObjectAdapter.
Where you already configure FreeMarker (NOT before each template processing), specify the objectWrapper to be a DefaultObjectWrapperWithJSONSupport.
There's a few non-obvious things with doing above properly, so I strongly recommend starting out from this example:
https://freemarker.apache.org/docs/pgui_datamodel_objectWrapper.html#pgui_datamodel_customObjectWrappingExample
Above linked example does the above 3 steps, but to support the Tupple class, instead of JSONObject. That's a TemplateSequenceModel, instead of TemplateHashModel, but otherwise what has to be done is very similar.
How can I distinguish in java graphQL if a parameter was explicitly set to null, or if it was not provided at all?
The use case that I try to achieve is the following: I have a mutation like this
updateUser(id:Int!, changes:UserChanges!)
#where UserChanges is defined as:
type UserChanges {
login:String
email:String
#etc
}
The idea here is that the user provides only the fields that he wants to change (like react setState for example).
So if email is ommited, I want to leave it unchanged.
But what if he/she wants to explicitly set email to null?
Is there any way figure this out from my resolver method and act accordingly?
(I use graphql-java-tools library)
I found the answer. In case somebody needs it:
An instance of graphql.schema.DataFetchingEnvironment is available to every resolver method.
This provides methods like getArguments(), hasArgument() etc.
Using those methods, we can find out if an argument was an explicit set to null, or if it was not provided at all.
Looks like deserialization from query/variables is handled by fasterxml Jackson, and that's proper place to deal with the issue, otherwise it becomes too complex: check every field? nested?
So: UserChanges.java should look like this:
class UserChanges {
// SHOULD NOT HAVE ALL ARGUMENT CONSTRUCTOR!
Optional<String> login;
Optional<String> email;
... getters & setters
}
in this case deserializer will use setters, ONLY FOR PROVIDED FIELDS!
And {"login":null} will become:
UserChanges.login = Optional.empty
UserChanges.email = null
First let me say that using Struts2 + Freemarker is a real blast.
Yet there's something is driving me crazy, because I cannot understand why it happens. I ask here as maybe someone else has an idea to share about it.
I've got an action, with a property.
Say
private String myText;
Then I've got a setter and a getter:
public void setMyText(String myText)
{
this.myText = myText;
}
public String getMyText()
{
if (myText == null)
myText = "(empty)";
return this.myText;
}
The result (in struts.xml) is a freemarker result.
So in my Freemarker template there's a line like the following:
<p>The text is: ${myText}</p>
Now consider I'm calling the action without any text parameter: say the url is
http:localhost:8080/myapp/myaction
As the getter provides a default value, when the action is processed and the result passed to my template, the property is set to the default; so I get (html on the browser side)
<p>The text is: (empty)</p>
If I call my action with the parameter set, instead (I mean with something like:
http:localhost:8080/myapp/myaction?myText=hallo
) things go wrong. Freemarker fires the following exception:
Exception occurred during processing request: For "${...}" content:
Expected a string or something automatically convertible to string
(number, date or boolean), but this has evaluated to a
sequence+extended_hash (String[] wrapped into f.e.b.ArrayModel)
It seems that "myText" is found twice...
What am I doing wrong? Or, at least, is there anyone that can explain to me why it happens?
P.S.: it's really found twice; the following is a way to workaround the problem:
<#if myText?is_sequence>${myText[0]}<#else>${myText}</#if>
Yet it seems to me not viable to wrap every variable in that way.
P.P.S.: a further hint: in the freemarker template there's a call to another action some lines before. Something like:
<#s.action var="innerAction" name="getTable" namespace="/foo" />
If I comment the line above, everything works fine.
The myText could be a variable from the freemarker context, but if you want to use action property
<p>The text is: ${action.myText}</p>
Note, that action prefix is not required to access action properties. A property resolution method is applied when resolving freemarker variables:
Property Resoloution:
Your action properties are automatically resolved - just like in a
velocity view.
for example ${name} will result in stack.findValue("name"), which
generally results in action.getName() being executed.
A search process is used to resolve the variable, searching the
following scopes in order, until a value is found :
freemarker variables
value stack
request attributes
session attributes
servlet context attributes
And later you can read what objects are accessible from the context.
Objects in the Context:
The following variables exist in the FreeMarker views
req - the current HttpServletRequest
res - the current HttpServletResponse
stack - the current OgnlValueStack
ognl - the OgnlTool instance
This class contains useful methods to execute OGNL expressions against arbitary objects, and a method to generate a select list using
the <s:select> pattern. (i.e. taking the name of the list property, a
listKey and listValue)
struts - an instance of StrutsBeanWrapper
action - the current Struts action
exception - optional the Exception instance, if the view is a JSP exception or Servlet exception view
The error might be caused by searches from the value stack and returning something that you didn't expect depending on the structure of the stack at the moment of execution.
Adding a prefix to the variable to point out the exact location of the property should fix the redundancy in the code when searching in the value stack.
i am using play framework , i need to check the user's permissions with #secure annotation , but i get a problem here :
#secure(UID=???)
public static void removeFavorite(Long storyId,Long userId){
}
can any one tell me how to pass the "userId" parameter to "UID" in the annotation ?
PS : the "userId" parameter is in request scope.
many thanks!
AFAIK you can't change annotations at runtime (at least not without dynamic code generation). Additionally, annotations are static, i.e. they apply to classes or class members (fields, methods etc.) and can't be changed per instance. Thus you can't pass the userId to that annotation.
I dont know what#securedoes, but generally, you'd read the annotation at runtime and optionally check its static parameters and if those checks succeed you'd read theuserId` parameter and do whatever is appropriate when that annotation is present.
I have a spring bound form (modelAttribute) which displays the user information.
The user's telephone number is displayed in a formatted manner but a requirement is that the number is saved to the database without any signs.
So in the getter method of my user object I format the telephone number according to the rules and in the setter I put the code to remove the special signs.
The formatting part works fine, but setter part where I remove the signs does not seem to occur.
In my constructor I also did:
setTelephoneNumber(TelephoneNumber);
So the constructor also invokes the setter.
I'm using Spring 3.0.4 and Spring-mvc.
Any input on this issue and how to resolve it would be appreciated.
edit:
controller section:
model.addAttribute("user", user);
JSP (shortened it a bit but this is the gist. submitUrl is due to a portal environment:
<form:form action="${submitUrl}" modelAttribute="user">
<form:input path="telephoneNumber"/>
</form>
Model telephoneNumber setter:
if(!StringUtils.isBlank(telephoneNumber)){
this.telephoneNumber = telephoneNumber.replaceAll("[^0-9]", "");
} else{
this.telephoneNumber= "";
}
And I think so because the value lands in the database with the formatting I used. (spacing)
Even if it is not the correct answer to your question:
I strongly recommend to do the formating in an other way then by setter getter
Spring 3.0 provideds something they called "type conversion"
spring blog with example
spring reference "Validation, Data Binding, and Type Conversion"
Using this would be much more cleaner.
Back to your question:
Spring path binding: is it bound directly to the variable or does it invoke the constructor/setters?
As fare I understand the Java Doc and some code snippets, Spring uses BeanWrapper (BeanWrapperImpl) to set the values of Beans (#see Reference: 5.4 Bean manipulation and the BeanWrapper). And BeanWrapperImpl behaves like the reference said:
uses setter and getter to access "simple" values.
It is exactly like the reference said in section "5.4.1 Setting and getting basic and nested properties": For an expression "name":
Indicates the property name
corresponding to the methods getName()
or isName() and setName(..)
So at least this answer your question, so I assume that the cause for your problem is some thing else.