dbarra / xdocreport

Automatically exported from code.google.com/p/xdocreport
1 stars 0 forks source link

Variable Name printed in report #236

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
What steps will reproduce the problem?
I am facing problem when object field has null value so it shows variable in 
generated report.FOr example if I have dateofBirth of client is null in 
dataabse for client object then report simply shows $client.DateOfBirth

Please let me know how can I fix this...

Thanks,
Priyanka

Original issue reported on code.google.com by davepriy...@gmail.com on 21 Mar 2013 at 7:20

GoogleCodeExporter commented 8 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

GoogleCodeExporter commented 8 years ago
Thanks for the solution....:)

Original comment by davepriy...@gmail.com on 21 Mar 2013 at 8:25

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
> 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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
>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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
I'm sorry, I don't see your attachment?

Original comment by angelo.z...@gmail.com on 22 Mar 2013 at 1:33

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago

Original comment by angelo.z...@gmail.com on 28 Mar 2013 at 2:21

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago
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

GoogleCodeExporter commented 8 years ago

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