Question

I am using ZK Charts to build HighCharts in my ZK framework. In Model Java File they are using Static block to load hard coded value in the model. For example

static {
    model = new DefaultCategoryModel();
    model.setValue("John", "Apples", new Integer(5));
    model.setValue("John", "Oranges", new Integer(3));
    model.setValue("John", "Pears", new Integer(4));
    model.setValue("John", "Grapes", new Integer(7));
    model.setValue("John", "Bananas", new Integer(2));
    model.setValue("Jane", "Apples", new Integer(2));
    model.setValue("Jane", "Oranges", new Integer(2));
    model.setValue("Jane", "Pears", new Integer(3));
    model.setValue("Jane", "Grapes", new Integer(2));
    model.setValue("Jane", "Bananas", new Integer(1));
    model.setValue("Joe", "Apples", new Integer(3));
    model.setValue("Joe", "Oranges", new Integer(4));
    model.setValue("Joe", "Pears", new Integer(4));
    model.setValue("Joe", "Grapes", new Integer(2));
    model.setValue("Joe", "Bananas", new Integer(5));
}

My charts are coming Fine but with default value. Now I want to make it dynamic. I have a couple of service which provide me stock level of products. The idea is I want to show low stock alerts using these graphs.

I am trying to call those services in the static block, But it is throwing Null Pointer Exception.

public class BarStackedData
{
private static CategoryModel model;

@Autowired
private static DefaultCustomCommerceCartService defaultCustomCommerceCartService;

@Autowired
private static ProductService productService;

static
{
    model = new DefaultCategoryModel();

    model.setValue(
            "Low Stock",
            "Puma T-Shirts",
            new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023506"),
                    null)));
    model.setValue(
            "Low Stock",
            "Socks",
            new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023206"),
                    null)));

    ....... more code .....

}

public static CategoryModel getCategoryModel()
{
    return model;
}

I know Static block is a static initializer. It will executed when the class is loaded. But Is there any way to make it dynamic Or how can I show those couple of graphs with dynamic values.

Log :

SEVERE: Servlet.service() for servlet [zkLoader] in context with path [/backoffice] threw       exception [Servlet java.lang.NullPointerException
    at com.rfn.model.BarStackedData.<clinit>(BarStackedData.java:30)
    at com.rfn.widgets.BarStackedComposerController.doAfterCompose(BarStackedComposerController.java:22)
    at com.rfn.widgets.BarStackedComposerController.doAfterCompose(BarStackedComposerController.java:1)
Was it helpful?

Solution 2

Why are you using Static block. You can get your job done without it also.

Try this ..

public class BarStackedData
{

   private static CategoryModel model;
   private static DefaultCustomCommerceCartService defaultCustomCommerceCartService;
   private static ProductService productService;

   public static CategoryModel getCategoryModel()
   {
        model = new DefaultCategoryModel();

        model.setValue(
        "Low Stock",
        "Puma T-Shirts",
        new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023506"),
                null)));
        model.setValue(
        "Low Stock",
        "Socks",
        new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023206"),
                null)));

      ....... more code .....

      return model;
   }

   // Getter Method
   public DefaultCustomCommerceCartService getDefaultCustomCommerceCartService()
   {
      return defaultCustomCommerceCartService;
   }

   // Setter Method
   public void setProductService(ProductService productService)
   {
      this.productService = productService;
   }

}

Now register bean in spring.xml file

<bean id="barStackedData" class="com.java.project.BarStackedData" >
    <property name="defaultCustomCommerceCartService" ref="defaultCustomCommerceCartService" />
    <property name="productService" ref="productService" />
</bean>

As I saw in ZK Chart they are using Controller. Try getting bean through Registry.

public class BarStackedComposer extends SelectorComposer<Window> 
{
@Wire
Charts chart;

BarStackedData barStackedData;

public void doAfterCompose(Window comp) throws Exception {
    super.doAfterCompose(comp);

    // get spring bean 
    barStackedData = (BarStackedData) Registry.getApplicationContext().getBean("barStackedData");

    chart.setModel(BarStackedData.getCategoryModel());

    chart.getYAxis().setMin(0);
    chart.getYAxis().setTitle("Total fruit consumption");

    chart.getLegend().setBackgroundColor("#FFFFFF");
    chart.getLegend().setReversed(true);

    chart.getPlotOptions().getSeries().setStacking("normal");

    chart.getCredits().setEnabled(false);
 }
}

Hope this will help you... enjoy :)

OTHER TIPS

The code in the static block is probably being executed before the variables that you are autowiring have been set - thus the NullPointerException.

You could try creating a method and annotating it with @PostConstruct and the method will be called by the framework after everything is configured correctly.

@Service
public class BarStackedData
{
    private CategoryModel model;

    @Autowired
    private DefaultCustomCommerceCartService defaultCustomCommerceCartService;

    @Autowired
    private ProductService productService;

    @PostConstruct
    private void setupModel()
    {
        model = new DefaultCategoryModel();

        model.setValue(
                "Low Stock",
                "Puma T-Shirts",
                new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023506"),
                null)));
        model.setValue(
                "Low Stock",
                "Socks",
                new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023206"),
                null)));

        ....... more code .....

    }

    public CategoryModel getCategoryModel()
    {
        return model;
    }
}

Edit

You have a requirement that the interface be via a static method so that the external charting library can access the data. Here's my solution which uses a facade class to keep the use of static methods away from the main service:

@Service
public class BarStackedData
{
    private CategoryModel model;

    @Autowired
    private DefaultCustomCommerceCartService defaultCustomCommerceCartService;

    @Autowired
    private ProductService productService;

    @PostConstruct
    private void setupModel()
    {
        model = new DefaultCategoryModel();

        model.setValue(
                "Low Stock",
                "Puma T-Shirts",
                new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023506"),
                null)));
        model.setValue(
                "Low Stock",
                "Socks",
                new Long(defaultCustomCommerceCartService.getCustomAvailableStockLevel(productService.getProductForCode("30023206"),
                null)));

        ....... more code .....

    }

    public CategoryModel getCategoryModel()
    {
        return model;
    }
}


@Component
public class DataFacade {

    private static BarStackedData barStackedModel = null;

    @Autowired
    private setBarStackedData(final BarStackedData barStackedModel) {
        DataFacade.barStackedModel = barStackedModel;
    }

    public static CategoryModel getCategoryModel() {
        return barStackedModel.getCategoryModel();
    }

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top