Search code examples
jasper-reports

How to add a custom/dynamic target to a hyperlink


I am using jasperreports-6.14.0. As far as I can tell, there is only one way to add a custom hyperlink target to anything that allows hyperlinks. Please tell me there is a better way (other than putting javascript into my reference expression).

  1. Implement the net.sf.jasperreports.engine.export.JRHyperlinkTargetProducer interface, looking in the hyperlink parameters for a specific, named parameter to return as your target string.
  2. Extend net.sf.jasperreports.engine.export.HtmlExporter and set its targetProducerFactory protected field as an instance of your new custom hyperlink target producer.

It looks like this is the only option, but it just feels like there should be a way to skip step 2 by just setting the targetProducerFactory. It's almost like the Jasper devs started to do exactly that and thought "Nah, I just don't feel right about that. Let's take it out."

I am going to do the above unless some kind soul can show me a better way.


Solution

  • Custom target producers are loaded as extensions by the HTML exporter. You can register extensions either programmatically by creating the HTML exporter using your own JasperReportsContext instance, or package the extension in a jar and have it autodetected by the exporter.

    If you control the HTML exporter creation you can pass the extension programmatically:

    JRHyperlinkTargetProducer targetProducer = new JRHyperlinkTargetProducer() {            
        @Override
        public String getHyperlinkTarget(JRPrintHyperlink hyperlink) {
            return "foo";
        }
    };
    JRHyperlinkTargetProducerMapFactory targetProducerFactory = new JRHyperlinkTargetProducerMapFactory();
    targetProducerFactory.addProducer("mycustomtarget", targetProducer);
    
    SimpleJasperReportsContext jasperReportsContext = new SimpleJasperReportsContext();
    jasperReportsContext.setExtensions(JRHyperlinkTargetProducerFactory.class, 
            Collections.singletonList(targetProducerFactory));
    
    HtmlExporter htmlExporter = new HtmlExporter(jasperReportsContext);
    

    If you want to have the extension autodected you need to create a jar that contains a class like this:

    public class CustomTargetProducerExtension implements ExtensionsRegistryFactory {
        @Override
        public ExtensionsRegistry createRegistry(String registryId, JRPropertiesMap properties) {
            JRHyperlinkTargetProducer targetProducer = new JRHyperlinkTargetProducer() {            
                @Override
                public String getHyperlinkTarget(JRPrintHyperlink hyperlink) {
                    return "bar";
                }
            };
            JRHyperlinkTargetProducerMapFactory targetProducerFactory = new JRHyperlinkTargetProducerMapFactory();
            targetProducerFactory.addProducer("mycustomtarget", targetProducer);
            
            return new SingletonExtensionRegistry<>(JRHyperlinkTargetProducerFactory.class, targetProducerFactory);
        }
    }
    

    And put a jasperreports_extension.properties resource in the root of the jar containing the line:

    net.sf.jasperreports.extension.registry.factory.my.custom.target.producer=<package>.CustomTargetProducerExtension
    

    Then your custom target producer would be automatically detected for elements that have hyperlinkTarget="mycustomtarget"