Closed GoogleCodeExporter closed 9 years ago
Hi to all, I faced with this problem before.
IT seems that Velocity can't treat null values, so the only solution I found is
to set null values to empty string.
Based on my little experience in XDocReport, I made conclusion that DataModel
which should go into velocity context(at generating document), should contain
only Strings, which are not null, this is because Velocity call for each object
toString method. So when it try to call dateofBirth.toString() inside of
velocity engine is throwed exception, which is catched, and logged, but not
throwed upper, so this is why you don't see this exception.
so, I see 2 solutions:
1. in you template check for null you fields
2. init you datamodel values with not null values.
I prefer second solution, just because it is more simple after to create report
template.
Cheers.
Hope my comment help someone.
P.S.
In my opinion this is not issue of the XDocReport, just because the template is
processed in template engine, and as XDocReport support Velocity, Freemarker
and possibly third party template engines, it will be a mess to do this
checking on XDocReport code, more than that, it should'n be done here.
P.P.S
Just check you template engine documentation about how it tread null fields.
Original comment by ruslancu...@gmail.com
on 21 Mar 2013 at 7:57
Thanks for the solution....:)
Original comment by davepriy...@gmail.com
on 21 Mar 2013 at 8:25
Hi Priyanka, ruslancusnir
@ruslancusnir : thank's for your comment.
I suppose that you are using Velocity as template engine (Freemarker throw
exception for null value by default), so I suggest you to read teh Velocity
User Guide http://velocity.apache.org/engine/devel/user-guide.html
You can find your answer too at
http://stackoverflow.com/questions/23853/how-i-hide-empty-velocity-variable-name
s
I'm not a big expert with Velocity, but if I understood the doc, try to write
your field like this :
-----------------------------------
$!{client.DateOfBirth}
-----------------------------------
So this solution is the 1) mean that ruslancusnir as explained (1. in you
template check for null you fields).
I agree with ruslancusnir, I don't like this solution because for a
not-developper, this syntax is complex.
But the solution 2) (init you datamodel values with not null values) can be
very boring when you have a big model (it's the same topic than DTO (Data
Transfert Object), using directly the model or create a DTO from the model to
use it in a view layer).
I have an idea to resolve this problem that I have started to explain at
https://code.google.com/p/xdocreport/issues/detail?id=41
The idea is to
1) use simple field name for the template document docx, odt (ex: $name) =>
it's the user (not a developer) who creates the template docx, odt.
2) manage a mapping beetween the field name and the (complex or not) data model
=> it's the goal of the developer.
For instance, you could write $name in the template docx, odt and the mapping
will replace $name by $!name, just by writing a mapping
-----------------------------------
fieldsmetadata.addMapping("$name", "$!name")
-----------------------------------
But it can be awfull to do that for the whole fields, so those mapping could be
generated automaticly by the fields metadata serializer (by using annotation,
using Class type)
Ex for Date Class type, we could generated automaticly the mapping
$myDate => $dateUtils.format($myDate, "DD/MM/YYY")
so you could write $myDate in your template docx, and use the model which
returns a date and format it with some pattern.
Regards Angelo
Original comment by angelo.z...@gmail.com
on 21 Mar 2013 at 8:34
hi,
Angelo, you solution is generally, but in my opinion is the same as solution 2,
but user will be confused, about why and how the null value is treated.
Now I working with images and I see that image have a null value behaviour.
How do you think if the same null value behaviour will be applied and for
regular field, not only for images?
In this case user himself will manage field null value by:
fieldMetadata.serNullValueBehaviour(Ignore); //this is not implemented, this is
just an proposal for API
I think that client sourcecode will become more short and clear, more than
that, adding this functinoality will easy permit to manage null value behaviour
using @FieldMetadata annotation.
Original comment by ruslancu...@gmail.com
on 21 Mar 2013 at 8:43
> Angelo, you solution is generally, but in my opinion is the same as solution 2
Yes it looks like, but whith FiedsMetadata you can manage automaticly the
behaviour for the whole fields (not need to create a new Pojo).
> user will be confused, about why and how the null value is treated.
for user, null or empty value, I think it's the same thing. With your Pojo
solution, it's the same problem. No?
> How do you think if the same null value behaviour will be applied and for
regular field, not only for images?
At first, I have done that for image, because I'm generating an XML fragment or
not according the behaviour. So the template engine cannot manage that. So I
have managed at hand the behaviour for image.
For null value field, template engine can manage that (ex : $!name). Your
proposition about fieldMetadata.serNullValueBehaviour(Ignore); will add ! or
not according the configuration, so it's the same thing than mapping. I would
like to avoid having a big API for FeildsMetadata (one user would like format
the date, an other would like format the double, etc). So if we add
setNullValueBehaviour, why not add too seDateFormat etc).
What do you think about that?
Regards Angelo
Original comment by angelo.z...@gmail.com
on 21 Mar 2013 at 9:00
Hello Angelo,
Thanks for your suggestions.
I will prefer to go with this solution.
fieldsmetadata.addMapping("$name", "$!name")
But I can not find method addMapping method for fieldsmetadata.
This is how I have created object of fieldsmetadata
FieldsMetadata fieldsMetadata = report.createFieldsMetadata();
Please let me know if this is not correct way.
Thanks,
Priyanka
Original comment by davepriy...@gmail.com
on 21 Mar 2013 at 9:09
Agree with you.. it is need to keep it as simple as it is possible, but:
1. formatting example: is already done with styles
2. in case of formatting the date is a special case
Treating null values is kind of global thing. And yes, as result we will have
same #!{ in the template, the question is about how simple we will get this
code in template.
But setNullValueBehaviour can help user to set default value(as from calling
directly this method as from @FieldMetadata annotation). in My proposal the
argument of the functino is an behaviour object, instead of Ignore can be
ThrowException or DefaultValue. So, user can manage null values, when with
mappings it can't be managed(especially for default value).
P.S.
In any case, I see that all our proposal's can be managed by solution 2 from my
comment #1.
Original comment by ruslancu...@gmail.com
on 21 Mar 2013 at 9:12
>I will prefer to go with this solution.
>fieldsmetadata.addMapping("$name", "$!name")
It's just an idea, it's not implemented.
> But setNullValueBehaviour can help user to set default value.
Ok, I understand. If we implemente dthat, I think we should implement mapping
before. setNullValueBehaviour will use mapping (or the Java code which replaces
field name by other directive template engine).
Original comment by angelo.z...@gmail.com
on 21 Mar 2013 at 9:21
Hello Angelo,
I am trying to making changes in docx template file with $!{client.DateOfBirth}
but it still doesn't work..
Could you please help me?
Thanks,
Priyanka
Original comment by davepriy...@gmail.com
on 21 Mar 2013 at 10:38
I have never used this syntax, I will try it when I will find time.
Regards Angelo
Original comment by angelo.z...@gmail.com
on 21 Mar 2013 at 10:53
Hello ruslancusnir,
I am trying to fix issue by checking null in template.But cant get it done.
I have used diff ways suggested in velocity template
$!client.DateOfBirth
#if($client.DateOfBirth)
$client.DateOfBirth
#end
But nothing works for me..If you have used null check in template then please
let me know how to do it.
Thanks,
Priyanka
Original comment by davepriy...@gmail.com
on 22 Mar 2013 at 11:22
Hi Priyanka,
Is it posible to attach your (simplify) docx + java code (Pojo+Java main) with
your case please.
I will try to see your problem.
Thank's
Regards Angelo
Original comment by angelo.z...@gmail.com
on 22 Mar 2013 at 11:46
Hello,
I am attaching dto and docx file and main code that generates report.
Thanks for your help.
Original comment by davepriy...@gmail.com
on 22 Mar 2013 at 1:31
I'm sorry, I don't see your attachment?
Original comment by angelo.z...@gmail.com
on 22 Mar 2013 at 1:33
I have tested quicly with our samples project name and it works great.
I have renamed the mergefield
--------------------
$project.Name
--------------------
with
--------------------
$!{project.Name}
--------------------
project.Name returns null and when report is generated there is blank value
instead of $project.Name
Are you sure that you are using mergefield to do that?
Original comment by angelo.z...@gmail.com
on 22 Mar 2013 at 3:10
Hello,
Thank you for looking at issue.
I was adding field from xdocreport fields menu directly by inserting field
not creating mergefield that's why it was not working.
I have created mergefield as per your suggestion and it works perfectly.
Thank you very much...:)
Original comment by davepriy...@gmail.com
on 23 Mar 2013 at 5:57
Original comment by angelo.z...@gmail.com
on 28 Mar 2013 at 2:21
Hello Angelo,
we "solved" this Problem this way:
IContext context = report.createContext();
EventCartridge eventCartridge = new EventCartridge();
eventCartridge.addEventHandler(new NullValueInsertionEventHandler());
eventCartridge.attachToContext((VelocityContext) context);
The class NullValueInsertionEventHandler implements
ReferenceInsertionEventHandler from Velocity that implements the bahavoiur of
Velocity.
public class NullValueInsertionEventHandler implements
ReferenceInsertionEventHandler {
@Override
public Object referenceInsert(String string, Object object) {
if (object == null) {
return "";
}
return object;
}
}
It was funny ot find out that our IContext ist an VelocityContext ;-))))
Best regards
Alexander
Original comment by googlec...@norz.de
on 5 Apr 2013 at 10:51
Hi Alexander,
Many thank's for your post. I think the clean solution is to configure
NullValueInsertionEventHandler in the velocity.properties.
Regards Angelo
Original comment by angelo.z...@gmail.com
on 5 Apr 2013 at 12:00
IContext context = report.createContext();
EventCartridge eventCartridge = new EventCartridge();
eventCartridge.addEventHandler(new NullValueInsertionEventHandler());
eventCartridge.attachToContext((VelocityContext) context);
The class NullValueInsertionEventHandler implements
ReferenceInsertionEventHandler from Velocity that implements the bahavoiur of
Velocity.
public class NullValueInsertionEventHandler implements
ReferenceInsertionEventHandler {
@Override
public Object referenceInsert(String string, Object object) {
if (object == null) {
return "";
}
return object;
}
}
Works well thanks !!!!
Original comment by ycelle...@gmail.com
on 26 Sep 2013 at 9:38
Original issue reported on code.google.com by
davepriy...@gmail.com
on 21 Mar 2013 at 7:20