Method to check if number is contained in ArrayList will not work, NullPointerExcepton. Can you use ArrayList method inside a constructed method? - arraylist

This is a project I am working on and it is supposed to take input from the user then which is an area code then see if it is contained in a array list. My method that I have created will not work in another class and I am not sure why, it is returning a NullPointerException.
The NullPointerException is shown at this line of code: if (mountainTime.contains(input))
This is the class with methods
package finalPro;
import java.util.ArrayList;
public class Final
{
public Final()
{
input = 0;
timezone = 0;
}
public void checkIfTrue(int y)
{
input = y;
if (mountainTime.contains(input))
{
timezone = 1;
}
else
timezone = 0;
System.out.println(timezone);
}
public int getZone()
{
return timezone;
}
public ArrayList<Integer> mountainTime;
private int input;
private int timezone;
}
Here is test class
package finalPro;
import java.util.ArrayList;
import javax.swing.JOptionPane;
public class FinalLogic
{
public static void main(String[] args)
{
ArrayList<Integer> mountainTime = new ArrayList<Integer>();
mountainTime.add(480);
mountainTime.add(602);
mountainTime.add(623); //Arizona area codes
mountainTime.add(928);
mountainTime.add(520);
mountainTime.add(303);
mountainTime.add(719); //Colorado
mountainTime.add(720);
mountainTime.add(970);
mountainTime.add(406); //Montana
mountainTime.add(505); //New Mexico
mountainTime.add(575);
mountainTime.add(385);
mountainTime.add(435); //Utah
mountainTime.add(801);
mountainTime.add(307); //Wyoming
Final myMap = new Final();
{
String x = JOptionPane.showInputDialog("Please enter a number: ");
int input = Integer.parseInt(x);
myMap.checkIfTrue(input);
}
}
}

I hope it's not too late, I haven't done anything special to fix your code, just some movement of code,
Removed the initialization logic from class FinalLogic to Final class .(btw Final name is not really good, you might be aware final is reserved word in Java. Although your name is case sensitive but still)
package finalPro;
import javax.swing.JOptionPane;
public class FinalLogic {
public static void main(String[] args) {
Final myMap = new Final();
String x = JOptionPane.showInputDialog("Please enter a number: ");
int input = Integer.parseInt(x);
myMap.checkIfTrue(input);
}
}
And here is your class Final
package finalPro;
import java.util.ArrayList;
public class Final {
public Final() {
input = 0;
timezone = 0;
// moved all initialization logic to constructor
mountainTime = new ArrayList<>();
mountainTime.add(480);
mountainTime.add(602);
mountainTime.add(623); // Arizona area codes
mountainTime.add(928);
mountainTime.add(520);
mountainTime.add(303);
mountainTime.add(719); // Colorado
mountainTime.add(720);
mountainTime.add(970);
mountainTime.add(406); // Montana
mountainTime.add(505); // New Mexico
mountainTime.add(575);
mountainTime.add(385);
mountainTime.add(435); // Utah
mountainTime.add(801);
mountainTime.add(307); // Wyoming
}
public void checkIfTrue(int y) {
input = y;
if (mountainTime.contains(input)) {
timezone = 1;
} else
timezone = 0;
System.out.println(timezone);
}
public int getZone() {
return timezone;
}
public ArrayList<Integer> mountainTime;
private int input;
private int timezone;
}
I tried in my workspace, it gives no NPE, Hope it helps.

Related

TornadoFX TableView. Scrolling the large amount of rows leads to UI freezing

I have a windows desktop application on Kotlin and I'm using JDK Zulu11 with JavaFX and TornadoFX 2.0.0.
I faced the problem with scrolling of large amount of rows (~4mln) in the TableView.
I have something like a player and when it starts I just need to do autoscroll to the row corresponding to the player current position. So to make playing smooth I do it by calling scrollTo method every 50 milliseconds, 20 times per second.
I observed that approximately at 300000 UI starts freezing and at 500000 it is almost dead.
When I increase the delay from 50ms to 200ms or 500ms the situation is the same, UI gets freeze.
When I used JDK Zulu1.8 with JavaFX and TornadoFX 1.7.2 just for check all was perfect, all is playing very smooth and fast enough. With Oracle JDK 1.8 all is ok also.
But I need to migrate to JDK 11 because I have some important dependencies.
So the question is what is wrong with JDK 11(JavaFX) and TornadoFX 2.0.0 and how it can be fixed?
Thanks a lot for any help.
PS: Here is the minimal reproducible example, I just found some TableView example on javacodegeeks and modified it, so please chek with JDK1.8 and with OpenJDK11, I used Azul Zulu 11.
Also here is the video with demonstration.
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventType;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.scene.paint.Color;
import javafx.scene.control.Label;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.control.TableColumn;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import java.util.List;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
public class FxTableViewExample1 extends Application {
public static class Book {
private SimpleIntegerProperty index;
private SimpleStringProperty title;
private SimpleStringProperty author;
public Book () {
}
public Book (Integer i, String s1, String s2) {
index = new SimpleIntegerProperty(i);
title = new SimpleStringProperty(s1);
author = new SimpleStringProperty(s2);
}
public int getIndex() {
return index.get();
}
public void setIndex(int index) {
this.index.set(index);
}
public String getTitle() {
return title.get();
}
public void setTitle(String s) {
title.set(s);
}
public String getAuthor() {
return author.get();
}
public void setAuthor(String s) {
author.set(s);
}
#Override
public String toString() {
return (index.get() + ": " + title.get() + ", by " + author.get());
}
}
private static final Integer COUNT = 10000000;
private static final Integer DELTA = 5000;
private static final Integer PERIOD = 50;
public static final EventType<Event> ScrollEventType = new EventType<>("ScrollEvent");
public static final EventType<Event> StopEventType = new EventType<>("StopEvent");
public static class ScrollEvent extends Event {
public Integer position = 0;
public ScrollEvent(Integer position) {
super(ScrollEventType);
this.position = position;
}
}
public static class StopEvent extends Event {
public StopEvent() {
super(StopEventType);
}
}
private TableView<Book> table;
private ObservableList<Book> data;
private Text actionStatus;
private Button startButton;
private Button stopButton;
private Integer count = 0;
private SimpleIntegerProperty currentPositionProperty = new SimpleIntegerProperty(0);
private Timer timer = null;
public static void main(String [] args) {
Application.launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Table View Example 1");
// Books label
Label label = new Label("Books");
label.setTextFill(Color.DARKBLUE);
label.setFont(Font.font("Calibri", FontWeight.BOLD, 36));
HBox labelHb = new HBox();
labelHb.setAlignment(Pos.CENTER);
labelHb.getChildren().add(label);
// Table view, data, columns and properties
table = new TableView<>();
data = getInitialTableData();
table.setItems(data);
TableColumn<Book, Integer> indexCol = new TableColumn<>("Index");
indexCol.setCellValueFactory(new PropertyValueFactory<Book, Integer>("index"));
TableColumn<Book, String> titleCol = new TableColumn<Book, String>("Title");
titleCol.setCellValueFactory(new PropertyValueFactory<Book, String>("title"));
TableColumn<Book, String> authorCol = new TableColumn<Book, String>("Author");
authorCol.setCellValueFactory(new PropertyValueFactory<Book, String>("author"));
table.getColumns().setAll(indexCol, titleCol, authorCol);
table.setPrefWidth(450);
table.setPrefHeight(300);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getSelectionModel().selectedIndexProperty().addListener(
new RowSelectChangeListener());
// Status message text
actionStatus = new Text();
actionStatus.setFill(Color.FIREBRICK);
startButton = new Button("Play");
stopButton = new Button("Stop");
stopButton.setDisable(true);
currentPositionProperty.addListener(new ChangeListener<Number>() {
#Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
Platform.runLater(new Runnable() {
#Override
public void run() {
table.scrollTo(newValue.intValue());
table.getSelectionModel().select(newValue.intValue());
}
});
}
});
primaryStage.addEventHandler(ScrollEventType, new EventHandler<Event>() {
#Override
public void handle(Event event) {
if (event.getEventType() == ScrollEventType) {
currentPositionProperty.set(((ScrollEvent)event).position);
}
}
});
primaryStage.addEventHandler(StopEventType, new EventHandler<Event>() {
#Override
public void handle(Event event) {
if (timer != null) {
timer.cancel();
timer = null;
}
}
});
startButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
count = 0;
startButton.setDisable(true);
stopButton.setDisable(false);
if (timer == null) {
timer = new Timer(true);
timer.schedule(new TimerTask() {
#Override
public void run() {
count++;
int position = count * DELTA;
if (position >= COUNT) {
Event.fireEvent(primaryStage, new ScrollEvent(COUNT));
Event.fireEvent(primaryStage, new StopEvent());
} else {
Event.fireEvent(primaryStage, new ScrollEvent(position));
}
}
}, 0, PERIOD);
}
}
});
stopButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
startButton.setDisable(false);
stopButton.setDisable(true);
if (timer != null) {
timer.cancel();
timer = null;
}
}
});
HBox hbox = new HBox(20);
hbox.setPadding(new Insets(25, 25, 25, 25));
hbox.getChildren().addAll(startButton, stopButton);
// Vbox
VBox vbox = new VBox(20);
vbox.setPadding(new Insets(25, 25, 25, 25));
vbox.getChildren().addAll(labelHb, table, actionStatus, hbox);
// Scene
Scene scene = new Scene(vbox, 500, 475); // w x h
primaryStage.setScene(scene);
primaryStage.show();
// Select the first row
table.getSelectionModel().select(0);
Book book = table.getSelectionModel().getSelectedItem();
actionStatus.setText(book.toString());
} // start()
private class RowSelectChangeListener implements ChangeListener<Number> {
#Override
public void changed(ObservableValue<? extends Number> ov,
Number oldVal, Number newVal) {
int ix = newVal.intValue();
if ((ix < 0) || (ix >= data.size())) {
return; // invalid data
}
Book book = data.get(ix);
actionStatus.setText(book.toString());
}
}
private ObservableList<Book> getInitialTableData() {
List<Book> list = new ArrayList<>();
int i = 0;
while (i < COUNT) {
list.add(new Book(i++, "The Thief", "Fuminori Nakamura"));
list.add(new Book(i++, "Of Human Bondage", "Somerset Maugham"));
list.add(new Book(i++, "The Bluest Eye", "Toni Morrison"));
list.add(new Book(i++, "I Am Ok You Are Ok", "Thomas Harris"));
list.add(new Book(i++, "Magnificent Obsession", "Lloyd C Douglas"));
list.add(new Book(i++, "100 Years of Solitude", "Gabriel Garcia Marquez"));
list.add(new Book(i++, "What the Dog Saw", "Malcolm Gladwell"));
list.add(new Book(i++, "The Fakir", "Ruzbeh Bharucha"));
list.add(new Book(i++, "The Hobbit", "J.R.R. Tolkien"));
list.add(new Book(i++, "Strange Life of Ivan Osokin", "P.D. Ouspensky"));
list.add(new Book(i++, "The Hunt for Red October", "Tom Clancy"));
list.add(new Book(i++, "Coma", "Robin Cook"));
}
return FXCollections.observableList(list);
}
}
The problem was resolved by using OpenJDK11 and separate OpenJFX15 instead of Zulu JDK11+JFX.

java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.util.List

I have a List<List<String>> dataTableList and I would like to get a specific list from there and put it on my List<String> dataList so that I could loop through that specific lists' value and alter it.
However, whenever I try to do that,I always get an error of:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to java.util.List.
Here's a sample of how I am trying to assign a specific list from dataTableList to dataList:
//First I looped through the List of Lists and called each list fetched as dataList
for(List<String> dataList : getTryLang().getDataTableList()){
//then, I created an iterator to be used later when I return the List I fetched with altered value
int iter = 0;
//next, I created a for-loop to iterate through the values of the List the I feched
for(int x; x < dataList.size(); x++){
//here, I formatted each value to amount or currency format.
dataList.set(x, getDataConvert().convertAmount(dataList.get(x)));
//finally, after I formatted everything, I returned it or set it to the specific index it's been located before
getTryLang().getDataTableList().set(iter, dataList);
}
iter++;
}
EDIT:
Here's my code and I modified some of it and didn't include some so that I could focus on expressing where the problem occurs.
Here's my TryLang.java:
#ManagedBean
#SessionScoped
public class TryLang implements Serializable {
public TryLang() {}
//declare
private List<List<String>> dataTableList;
//getter setter
public List<List<String>> getDataTableList() {
return dataTableList == null ? dataTableList = new ArrayList<>() : dataTableList;
}
public void setDataTableList(List<List<String>> dataTableList) {
this.dataTableList = dataTableList;
}
}
Then here's my BookOfAccountsController.java:
#ManagedBean
#RequestScoped
public class BooksOfAccountsController implements Serializable {
public BooksOfAccountsController() {}
//declare
#ManagedProperty(value = "#{dataConvert}")
private DataConvert dataConvert;
#ManagedProperty(value = "#{tryLang}")
private TryLang tryLang;
//getter setter NOTE: I wouldn't include other getter setters to shorten the code here :)
public TryLang getTryLang() {
return tryLang == null ? tryLang = new TryLang() : tryLang;
}
public void setTryLang(TryLang tryLang) {
this.tryLang = tryLang;
}
//I would just go straight to the method instead
public void runBooksOfAccounts() throws SystemException, SQLException {
//So there are dbCons here to connect on my DB and all. And I'll just go straight on where the List<List<String>> is being set
//Here's where the List<List<String>> is being set
getTryLang().setDataTableList(getCemf().getFdemf().createEntityManager().createNativeQuery("SELECT crj.* FROM crj_rep crj").getResultList());
getTryLang().setDataTableColumns(getCemf().getFdemf().createEntityManager().createNativeQuery("SELECT col.column_name FROM information_schema.columns col WHERE table_schema = 'public' AND table_name = 'crj_rep'").getResultList());
for (int x = 0; x < getTryLang().getDataTableColumns().size(); x++) {
try {
Integer.parseInt(getTryLang().getDataTableColumns().get(x));
getTryLang().getDataTableColumns().set(x, getDataConvert().accountCodeConvert(getTryLang().getDataTableColumns().get(x)));
//then here is where the error points at
for (List<String> dataList : getTryLang().getDataTableList()) {
try{
int iter = 0;
dataList.set(x, getDataConvert().convertAmount(new BigDecimal(dataList.get(x))));
getTryLang().getDataTableList().set(iter, dataList);
iter++;
}catch(ClassCastException ne){
System.out.println("cannot convert " + ne);
}
}
} catch (NumberFormatException ne) {
//print the error
}
}
}
}

Spring AOP - passing arguments between annotated methods

i've written a utility to monitor individual business transactions. For example, Alice calls a method which calls more methods and i want info on just Alice's call, separate from Bob's call to the same method.
Right now the entry point creates a Transaction object and it's passed as an argument to each method:
class Example {
public Item getOrderEntryPoint(int orderId) {
Transaction transaction = transactionManager.create();
transaction.trace("getOrderEntryPoint");
Order order = getOrder(orderId, transaction);
transaction.stop();
logger.info(transaction);
return item;
}
private Order getOrder(int orderId, Transaction t) {
t.trace("getOrder");
Order order = getItems(itemId, t);
t.addStat("number of items", order.getItems().size());
for (Item item : order.getItems()) {
SpecialOffer offer = getSpecialOffer(item, t);
if (null != offer) {
t.incrementStat("offers", 1);
}
}
t.stop();
return order;
}
private SpecialOffer getSpecialOffer(Item item, Transaction t) {
t.trace("getSpecialOffer(" + item.id + ")", TraceCategory.Database);
return offerRepository.getByItem(item);
t.stop();
}
}
This will print to the log something like:
Transaction started by Alice at 10:42
Statistics:
number of items : 3
offers : 1
Category Timings (longest first):
DB : 2s 903ms
code : 187ms
Timings (longest first):
getSpecialOffer(1013) : 626ms
getItems : 594ms
Trace:
getOrderEntryPoint (7ms)
getOrder (594ms)
getSpecialOffer(911) (90ms)
getSpecialOffer(1013) (626ms)
getSpecialOffer(2942) (113ms)
It works great but passing the transaction object around is ugly. Someone suggested AOP but i don't see how to pass the transaction created in the first method to all the other methods.
The Transaction object is pretty simple:
public class Transaction {
private String uuid = UUID.createRandom();
private List<TraceEvent> events = new ArrayList<>();
private Map<String,Int> stats = new HashMap<>();
}
class TraceEvent {
private String name;
private long durationInMs;
}
The app that uses it is a Web app, and this multi-threaded, but the individual transactions are on a single thread - no multi-threading, async code, competition for resources, etc.
My attempt at an annotation:
#Around("execution(* *(..)) && #annotation(Trace)")
public Object around(ProceedingJoinPoint point) {
String methodName = MethodSignature.class.cast(point.getSignature()).getMethod().getName();
//--- Where do i get this call's instance of TRANSACTION from?
if (null == transaction) {
transaction = TransactionManager.createTransaction();
}
transaction.trace(methodName);
Object result = point.proceed();
transaction.stop();
return result;
Introduction
Unfortunately, your pseudo code does not compile. It contains several syntactical and logical errors. Furthermore, some helper classes are missing. If I did not have spare time today and was looking for a puzzle to solve, I would not have bothered making my own MCVE out of it, because that would actually have been your job. Please do read the MCVE article and learn to create one next time, otherwise you will not get a lot of qualified help here. This was your free shot because you are new on SO.
Original situation: passing through transaction objects in method calls
Application helper classes:
package de.scrum_master.app;
public class Item {
private int id;
public Item(int id) {
this.id = id;
}
public int getId() {
return id;
}
#Override
public String toString() {
return "Item[id=" + id + "]";
}
}
package de.scrum_master.app;
public class SpecialOffer {}
package de.scrum_master.app;
public class OfferRepository {
public SpecialOffer getByItem(Item item) {
if (item.getId() < 30)
return new SpecialOffer();
return null;
}
}
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
public class Order {
private int id;
public Order(int id) {
this.id = id;
}
public List<Item> getItems() {
List<Item> items = new ArrayList<>();
int offset = id == 12345 ? 0 : 1;
items.add(new Item(11 + offset, this));
items.add(new Item(22 + offset, this));
items.add(new Item(33 + offset, this));
return items;
}
}
Trace classes:
package de.scrum_master.trace;
public enum TraceCategory {
Code, Database
}
package de.scrum_master.trace;
class TraceEvent {
private String name;
private TraceCategory category;
private long durationInMs;
private boolean finished = false;
public TraceEvent(String name, TraceCategory category, long startTime) {
this.name = name;
this.category = category;
this.durationInMs = startTime;
}
public long getDurationInMs() {
return durationInMs;
}
public void setDurationInMs(long durationInMs) {
this.durationInMs = durationInMs;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
#Override
public String toString() {
return "TraceEvent[name=" + name + ", category=" + category +
", durationInMs=" + durationInMs + ", finished=" + finished + "]";
}
}
Transaction classes:
Here I tried to mimic your own Transaction class with as few as possible changes, but there was a lot I had to add and modify in order to emulate a simplified version of your trace output. This is not thread-safe and the way I am locating the last unfinished TraceEvent is not nice and only works cleanly if there are not exceptions. But you get the idea, I hope. The point is to just make it basically work and subsequently get log output similar to your example. If this was originally my code, I would have solved it differently.
package de.scrum_master.trace;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.UUID;
public class Transaction {
private String uuid = UUID.randomUUID().toString();
private List<TraceEvent> events = new ArrayList<>();
private Map<String, Integer> stats = new HashMap<>();
public void trace(String message) {
trace(message, TraceCategory.Code);
}
public void trace(String message, TraceCategory category) {
events.add(new TraceEvent(message, category, System.currentTimeMillis()));
}
public void stop() {
TraceEvent event = getLastUnfinishedEvent();
event.setDurationInMs(System.currentTimeMillis() - event.getDurationInMs());
event.setFinished(true);
}
private TraceEvent getLastUnfinishedEvent() {
return events
.stream()
.filter(event -> !event.isFinished())
.reduce((first, second) -> second)
.orElse(null);
}
public void addStat(String text, int size) {
stats.put(text, size);
}
public void incrementStat(String text, int increment) {
Integer currentCount = stats.get(text);
if (currentCount == null)
currentCount = 0;
stats.put(text, currentCount + increment);
}
#Override
public String toString() {
return "Transaction {" +
toStringUUID() +
toStringStats() +
toStringEvents() +
"\n}\n";
}
private String toStringUUID() {
return "\n uuid = " + uuid;
}
private String toStringStats() {
String result = "\n stats = {";
for (Entry<String, Integer> statEntry : stats.entrySet())
result += "\n " + statEntry;
return result + "\n }";
}
private String toStringEvents() {
String result = "\n events = {";
for (TraceEvent event : events)
result += "\n " + event;
return result + "\n }";
}
}
package de.scrum_master.trace;
public class TransactionManager {
public Transaction create() {
return new Transaction();
}
}
Example driver application:
package de.scrum_master.app;
import de.scrum_master.trace.TraceCategory;
import de.scrum_master.trace.Transaction;
import de.scrum_master.trace.TransactionManager;
public class Example {
private TransactionManager transactionManager = new TransactionManager();
private OfferRepository offerRepository = new OfferRepository();
public Order getOrderEntryPoint(int orderId) {
Transaction transaction = transactionManager.create();
transaction.trace("getOrderEntryPoint");
sleep(100);
Order order = getOrder(orderId, transaction);
transaction.stop();
System.out.println(transaction);
return order;
}
private Order getOrder(int orderId, Transaction t) {
t.trace("getOrder");
sleep(200);
Order order = new Order(orderId);
t.addStat("number of items", order.getItems().size());
for (Item item : order.getItems()) {
SpecialOffer offer = getSpecialOffer(item, t);
if (null != offer)
t.incrementStat("special offers", 1);
}
t.stop();
return order;
}
private SpecialOffer getSpecialOffer(Item item, Transaction t) {
t.trace("getSpecialOffer(" + item.getId() + ")", TraceCategory.Database);
sleep(50);
SpecialOffer specialOffer = offerRepository.getByItem(item);
t.stop();
return specialOffer;
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Example().getOrderEntryPoint(12345);
new Example().getOrderEntryPoint(23456);
}
}
If you run this code, the output is as follows:
Transaction {
uuid = 62ec9739-bd32-4a56-b6b3-a8a13624961a
stats = {
special offers=2
number of items=3
}
events = {
TraceEvent[name=getOrderEntryPoint, category=Code, durationInMs=561, finished=true]
TraceEvent[name=getOrder, category=Code, durationInMs=451, finished=true]
TraceEvent[name=getSpecialOffer(11), category=Database, durationInMs=117, finished=true]
TraceEvent[name=getSpecialOffer(22), category=Database, durationInMs=69, finished=true]
TraceEvent[name=getSpecialOffer(33), category=Database, durationInMs=63, finished=true]
}
}
Transaction {
uuid = a420cd70-96e5-44c4-a0a4-87e421d05e87
stats = {
special offers=2
number of items=3
}
events = {
TraceEvent[name=getOrderEntryPoint, category=Code, durationInMs=469, finished=true]
TraceEvent[name=getOrder, category=Code, durationInMs=369, finished=true]
TraceEvent[name=getSpecialOffer(12), category=Database, durationInMs=53, finished=true]
TraceEvent[name=getSpecialOffer(23), category=Database, durationInMs=63, finished=true]
TraceEvent[name=getSpecialOffer(34), category=Database, durationInMs=53, finished=true]
}
}
AOP refactoring
Preface
Please note that I am using AspectJ here because two things about your code would never work with Spring AOP because it works with a delegation pattern based on dynamic proxies:
self-invocation (internally calling a method of the same class or super-class)
intercepting private methods
Because of these Spring AOP limitations I advise you to either refactor your code so as to avoid the two issues above or to configure your Spring applications to use full AspectJ via LTW (load-time weaving) instead.
As you noticed, my sample code does not use Spring at all because AspectJ is completely independent of Spring and works with any Java application (or other JVM languages, too).
Refactoring idea
Now what should you do in order to get rid of passing around tracing information (Transaction objects), polluting your core application code and tangling it with trace calls?
You extract transaction tracing into an aspect taking care of all trace(..) and stop() calls.
Unfortunately your Transaction class contains different types of information and does different things, so you cannot completely get rid of context information about how to trace for each affected method. But at least you can extract that context information from the method bodies and transform it into a declarative form using annotations with parameters.
These annotations can be targeted by an aspect taking care of handling transaction tracing.
Added and updated code, iteration 1
Annotations related to transaction tracing:
package de.scrum_master.trace;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface TransactionEntryPoint {}
package de.scrum_master.trace;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface TransactionTrace {
String message() default "__METHOD_NAME__";
TraceCategory category() default TraceCategory.Code;
String addStat() default "";
String incrementStat() default "";
}
Refactored application classes with annotations:
package de.scrum_master.app;
import java.util.ArrayList;
import java.util.List;
import de.scrum_master.trace.TransactionTrace;
public class Order {
private int id;
public Order(int id) {
this.id = id;
}
#TransactionTrace(message = "", addStat = "number of items")
public List<Item> getItems() {
List<Item> items = new ArrayList<>();
int offset = id == 12345 ? 0 : 1;
items.add(new Item(11 + offset));
items.add(new Item(22 + offset));
items.add(new Item(33 + offset));
return items;
}
}
Nothing much here, only added an annotation to getItems(). But the sample application class changes massively, getting much cleaner and simpler:
package de.scrum_master.app;
import de.scrum_master.trace.TraceCategory;
import de.scrum_master.trace.TransactionEntryPoint;
import de.scrum_master.trace.TransactionTrace;
public class Example {
private OfferRepository offerRepository = new OfferRepository();
#TransactionEntryPoint
#TransactionTrace
public Order getOrderEntryPoint(int orderId) {
sleep(100);
Order order = getOrder(orderId);
return order;
}
#TransactionTrace
private Order getOrder(int orderId) {
sleep(200);
Order order = new Order(orderId);
for (Item item : order.getItems()) {
SpecialOffer offer = getSpecialOffer(item);
// Do something with special offers
}
return order;
}
#TransactionTrace(category = TraceCategory.Database, incrementStat = "specialOffers")
private SpecialOffer getSpecialOffer(Item item) {
sleep(50);
SpecialOffer specialOffer = offerRepository.getByItem(item);
return specialOffer;
}
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
new Example().getOrderEntryPoint(12345);
new Example().getOrderEntryPoint(23456);
}
}
See? Except for a few annotations there is nothing left of the transaction tracing logic, the application code only takes care of its core concern. If you also remove the sleep() method which only makes the application slower for demonstration purposes (because we want some nice statistics with measured times >0 ms), the class gets even more compact.
But of course we need to put the transaction tracing logic somewhere, more precisely modularise it into an AspectJ aspect:
Transaction tracing aspect:
package de.scrum_master.trace;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.stream.Collectors;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
#Aspect("percflow(entryPoint())")
public class TransactionTraceAspect {
private static TransactionManager transactionManager = new TransactionManager();
private Transaction transaction = transactionManager.create();
#Pointcut("execution(* *(..)) && #annotation(de.scrum_master.trace.TransactionEntryPoint)")
private static void entryPoint() {}
#Around("execution(* *(..)) && #annotation(transactionTrace)")
public Object doTrace(ProceedingJoinPoint joinPoint, TransactionTrace transactionTrace) throws Throwable {
preTrace(transactionTrace, joinPoint);
Object result = joinPoint.proceed();
postTrace(transactionTrace);
addStat(transactionTrace, result);
incrementStat(transactionTrace, result);
return result;
}
private void preTrace(TransactionTrace transactionTrace, ProceedingJoinPoint joinPoint) {
String traceMessage = transactionTrace.message();
if ("".equals(traceMessage))
return;
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
if ("__METHOD_NAME__".equals(traceMessage)) {
traceMessage = signature.getName() + "(";
traceMessage += Arrays.stream(joinPoint.getArgs()).map(arg -> arg.toString()).collect(Collectors.joining(", "));
traceMessage += ")";
}
transaction.trace(traceMessage, transactionTrace.category());
}
private void postTrace(TransactionTrace transactionTrace) {
if ("".equals(transactionTrace.message()))
return;
transaction.stop();
}
private void addStat(TransactionTrace transactionTrace, Object result) {
if ("".equals(transactionTrace.addStat()) || result == null)
return;
if (result instanceof Collection)
transaction.addStat(transactionTrace.addStat(), ((Collection<?>) result).size());
else if (result.getClass().isArray())
transaction.addStat(transactionTrace.addStat(), Array.getLength(result));
}
private void incrementStat(TransactionTrace transactionTrace, Object result) {
if ("".equals(transactionTrace.incrementStat()) || result == null)
return;
transaction.incrementStat(transactionTrace.incrementStat(), 1);
}
#After("entryPoint()")
public void logFinishedTransaction(JoinPoint joinPoint) {
System.out.println(transaction);
}
}
Let me explain what this aspect does:
#Pointcut(..) entryPoint() says: Find me all methods in the code annotated by #TransactionEntryPoint. This pointcut is used in two places:
#Aspect("percflow(entryPoint())") says: Create one aspect instance for each control flow beginning at a transaction entry point.
#After("entryPoint()") logFinishedTransaction(..) says: Execute this advice (AOP terminology for a method linked to a pointcut) after an entry point methods is finished. The corresponding method just prints the transaction statistics just like in the original code at the end of Example.getOrderEntryPoint(..).
#Around("execution(* *(..)) && #annotation(transactionTrace)") doTrace(..)says: Wrap methods annotated by TransactionTrace and do the following (method body):
add new trace element and start measuring time
execute original (wrapped) method and store result
update trace element with measured time
add one type of statistics (optional)
increment another type of statistics (optional)
return wrapped method's result to its caller
The private methods are just helpers for the #Around advice.
The console log when running the updated Example class and active AspectJ is:
Transaction {
uuid = 4529d325-c604-441d-8997-45ca659abb14
stats = {
specialOffers=2
number of items=3
}
events = {
TraceEvent[name=getOrderEntryPoint(12345), category=Code, durationInMs=468, finished=true]
TraceEvent[name=getOrder(12345), category=Code, durationInMs=366, finished=true]
TraceEvent[name=getSpecialOffer(Item[id=11]), category=Database, durationInMs=59, finished=true]
TraceEvent[name=getSpecialOffer(Item[id=22]), category=Database, durationInMs=50, finished=true]
TraceEvent[name=getSpecialOffer(Item[id=33]), category=Database, durationInMs=51, finished=true]
}
}
Transaction {
uuid = ef76a996-8621-478b-a376-e9f7a729a501
stats = {
specialOffers=2
number of items=3
}
events = {
TraceEvent[name=getOrderEntryPoint(23456), category=Code, durationInMs=452, finished=true]
TraceEvent[name=getOrder(23456), category=Code, durationInMs=351, finished=true]
TraceEvent[name=getSpecialOffer(Item[id=12]), category=Database, durationInMs=50, finished=true]
TraceEvent[name=getSpecialOffer(Item[id=23]), category=Database, durationInMs=50, finished=true]
TraceEvent[name=getSpecialOffer(Item[id=34]), category=Database, durationInMs=50, finished=true]
}
}
You see, it looks almost identical to the original application.
Idea for further simplification, iteration 2
When reading method Example.getOrder(int orderId) I was wondering why you are calling order.getItems(), looping over it and calling getSpecialOffer(item) inside the loop. In your sample code you do not use the results for anything other than updating the transaction trace object. I am assuming that in your real code you do something with the order and with the special offers in that method.
But just in case you really do not need those calls inside that method, I suggest
you factor the calls out right into the aspect, getting rid of the TransactionTrace annotation parameters String addStat() and String incrementStat().
The Example code would get even simpler and
the annotation #TransactionTrace(message = "", addStat = "number of items") in class would go away, too.
I am leaving this refactoring to you if you think it makes sense.

Unable to identify where a NullPointerException is coming from

so I am getting the following error:
Exception in thread "Thread-0" java.lang.NullPointerException
at dev.tamir.firstgame.entities.creatures.Player.getInput(Player.java:19)
at dev.tamir.firstgame.entities.creatures.Player.tick(Player.java:31)
at dev.tamir.firstgame.states.GameState.tick(GameState.java:25)
at dev.tamir.firstgame.Game.tick(Game.java:65)
at dev.tamir.firstgame.Game.run(Game.java:110)
at java.lang.Thread.run(Unknown Source)
And I've checked all the lines Java had marked me and I can not find what is producing the null.
Player:
package dev.tamir.firstgame.entities.creatures;
import java.awt.Graphics;
import dev.tamir.firstgame.Game;
import dev.tamir.firstgame.gfx.Assets;
public class Player extends Creature {
private Game game;
public Player(Game game, float x, float y) {
super(game, x, y, Creature.DEFAULT_CREATURE_WIDTH, Creature.DEFAULT_CREATURE_HEIGHT);
}
#Override
public void tick() {
getInput();
move();
game.getGameCamera().centerOnEntity(this);
}
private void getInput() {
xMove = 0;
yMove = 0;
if(game.getKeyManager().up)
yMove = -speed;
if(game.getKeyManager().down)
yMove = speed;
if(game.getKeyManager().left)
xMove = -speed;
if(game.getKeyManager().right)
xMove = speed;
}
#Override
public void render(Graphics g) {
g.drawImage(Assets.robro[7], (int) (x - game.getGameCamera().getxOffset()), (int) (y - game.getGameCamera().getyOffset()), width, height, null);
}
}
Gamestate:
package dev.tamir.firstgame.states;
import java.awt.Graphics;
import dev.tamir.firstgame.Game;
import dev.tamir.firstgame.entities.creatures.Player;
import dev.tamir.firstgame.tiles.Tile;
import dev.tamir.firstgame.worlds.World;
public class GameState extends State {
private Player player;
private World world;
public GameState(Game game) {
super(game);
player = new Player(game, 0, 0);
world = new World(game, "res/worlds/world1.txt");
}
#Override
public void tick() {
world.tick();
player.tick();
}
#Override
public void render(Graphics g) {
world.render(g);
player.render(g);
}
}
Game:
package dev.tamir.firstgame;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;
import dev.tamir.firstgame.Display.Display;
import dev.tamir.firstgame.gfx.Assets;
import dev.tamir.firstgame.gfx.GameCamera;
import dev.tamir.firstgame.input.KeyManager;
import dev.tamir.firstgame.states.GameState;
import dev.tamir.firstgame.states.MenuState;
import dev.tamir.firstgame.states.State;
public class Game implements Runnable {
private Display display;
private Thread thread;
private BufferStrategy bs;
private Graphics g;
//States
private State gameState;
private State menuState;
//Input
private KeyManager keyManager;
//Camera
private GameCamera gameCamera;
private boolean running = false;
private int width, height;
public String title;
public Game(String title, int width, int height) {
this.width = width;
this.height = height;
this.title = title;
keyManager = new KeyManager();
}
private void init() {
display = new Display(title, width, height);
display.getFrame().addKeyListener(keyManager);
Assets.init();
gameCamera = new GameCamera(this, 0,0);
gameState = new GameState(this);
menuState = new MenuState(this);
State.setState(gameState);
}
private void tick() {
keyManager.tick();
if(State.getState() != null)
State.getState().tick();
}
private void render() {
bs = display.getCanvas().getBufferStrategy();
if(bs == null) {
display.getCanvas().createBufferStrategy(3);
return;
}
g = bs.getDrawGraphics();
//Clear
g.clearRect(0, 0, width, height);
//Draw
if(State.getState() != null)
State.getState().render(g);
//End of Draw
bs.show();
g.dispose();
}
public void run() {
init();
int fps = 60;
double timePerTick = 1000000000 / fps;
double delta = 0;
long now;
long lastTime = System.nanoTime();
long timer = 0;
int ticks = 0;
while (running) {
now = System.nanoTime();
delta += (now - lastTime) / timePerTick;
timer += now - lastTime;
lastTime = now;
if(delta >= 1) {
tick();
render();
ticks++;
delta--;
}
if(timer >= 1000000000) {
System.out.println("FPS: " + ticks );
ticks = 0;
timer = 0;
}
}
stop();
}
public KeyManager getKeyManager() {
return keyManager;
}
public GameCamera getGameCamera() {
return gameCamera;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public synchronized void start() {
if (running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
public synchronized void stop() {
if (!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
help would be very appreciated, as I've been looking for hours now and I don't know what is causing the null and I am suspecting the error log may even be misleading me.
My guess would be you have a private Game in your creature class. When you call super() in Player, you pass a Game object to Creature. The Creature constructor most likely has a line like this.game = game;
Of course, I can't say for sure because the Creature class is not included in your post, but that's the most likely code setup. Because game would then be private to Creature, Player cannot see it. That means the private Game game that you declare in Player is never set.
After you call super, do this.game = game;
This will almost certainly take care of your issue.
Just for future reference, the message you got when the error resulted is the call stack; basically it tells you what methods called what, the most recent being at the top. The error took place at line 19 in Player.getInput(), which was called by tick() in that same class.
The only object you use in getInput() is game, and so that must be the source of the null pointer. From there, it's a quick check to see that game is a private field of Player, and since it is null that's a huge clue that it was never initialized (though that is not always the case). Private fields most often are initialized in the class constuctor (but they don't have to be... your Player class is pretty sparse so it wouldn't take that long to look through all of it if you absolutly had to. Looking at the Player constructor, we see a Game object named game is passed in, which suggests that it was intended to be used to initialize game and yet never is. Voilà, we found the problem!
I'm sorry if that last paragraph felt a little condecending; it wasn't meant to be. I just wanted to walk you through how I found your issue. Hopefully knowing how I found it will help you find later errors on your own.

AbstractStringBuilder.ensureCapacityInternal get NullPointerException in storm bolt

online system, the storm Bolt get NullPointerException,though I think I check it before line 61; It gets NullPointerException once in a while;
import ***.KeyUtils;
import ***.redis.PipelineHelper;
import ***.redis.PipelinedCacheClusterClient;
import **.redis.R2mClusterClient;
import org.apache.commons.lang3.StringUtils;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.IRichBolt;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.tuple.Tuple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Map;
/**
* RedisBolt batch operate
*/
public class RedisBolt implements IRichBolt {
static final long serialVersionUID = 737015318988609460L;
private static ApplicationContext applicationContext;
private static long logEmitNumber = 0;
private static StringBuffer totalCmds = new StringBuffer();
private Logger logger = LoggerFactory.getLogger(getClass());
private OutputCollector _collector;
private R2mClusterClient r2mClusterClient;
#Override
public void prepare(Map map, TopologyContext topologyContext, OutputCollector outputCollector) {
_collector = outputCollector;
if (applicationContext == null) {
applicationContext = new ClassPathXmlApplicationContext("spring/spring-config-redisbolt.xml");
}
if (r2mClusterClient == null) {
r2mClusterClient = (R2mClusterClient) applicationContext.getBean("r2mClusterClient");
}
}
#Override
public void execute(Tuple tuple) {
String log = tuple.getString(0);
String lastCommands = tuple.getString(1);
try {
//log count
if (StringUtils.isNotEmpty(log)) {
logEmitNumber++;
}
if (StringUtils.isNotEmpty(lastCommands)) {
if(totalCmds==null){
totalCmds = new StringBuffer();
}
totalCmds.append(lastCommands);//line 61
}
//日志数量控制
int numberLimit = 1;
String flow_log_limit = r2mClusterClient.get(KeyUtils.KEY_PIPELINE_LIMIT);
if (StringUtils.isNotEmpty(flow_log_limit)) {
try {
numberLimit = Integer.parseInt(flow_log_limit);
} catch (Exception e) {
numberLimit = 1;
logger.error("error", e);
}
}
if (logEmitNumber >= numberLimit) {
StringBuffer _totalCmds = new StringBuffer(totalCmds);
try {
//pipeline submit
PipelinedCacheClusterClient pip = r2mClusterClient.pipelined();
String[] commandArray = _totalCmds.toString().split(KeyUtils.REDIS_CMD_SPILT);
PipelineHelper.cmd(pip, commandArray);
pip.sync();
pip.close();
totalCmds = new StringBuffer();
} catch (Exception e) {
logger.error("error", e);
}
logEmitNumber = 0;
}
} catch (Exception e) {
logger.error(new StringBuffer("====RedisBolt error for log=[ ").append(log).append("] \n commands=[").append(lastCommands).append("]").toString(), e);
_collector.reportError(e);
_collector.fail(tuple);
}
_collector.ack(tuple);
}
#Override
public void cleanup() {
}
#Override
public void declareOutputFields(OutputFieldsDeclarer outputFieldsDeclarer) {
}
#Override
public Map<String, Object> getComponentConfiguration() {
return null;
}
}
exception info:
java.lang.NullPointerException at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:113) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415) at java.lang.StringBuffer.append(StringBuffer.java:237) at com.jd.jr.dataeye.storm.bolt.RedisBolt.execute(RedisBolt.java:61) at org.apache.storm.daemon.executor$fn__5044$tuple_action_fn__5046.invoke(executor.clj:727) at org.apache.storm.daemon.executor$mk_task_receiver$fn__4965.invoke(executor.clj:459) at org.apache.storm.disruptor$clojure_handler$reify__4480.onEvent(disruptor.clj:40) at org.apache.storm.utils.DisruptorQueue.consumeBatchToCursor(DisruptorQueue.java:472) at org.apache.storm.utils.DisruptorQueue.consumeBatchWhenAvailable(DisruptorQueue.java:451) at org.apache.storm.disruptor$consume_batch_when_available.invoke(disruptor.clj:73) at org.apache.storm.daemon.executor$fn__5044$fn__5057$fn__5110.invoke(executor.clj:846) at org.apache.storm.util$async_loop$fn__557.invoke(util.clj:484) at clojure.lang.AFn.run(AFn.java:22) at java.lang.Thread.run(Thread.java:745)
can anyone give me some advice to find the reason.
That is really odd thing to happen. Please read the code for two classes.
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/lang/AbstractStringBuilder.java
https://github.com/openjdk-mirror/jdk7u-jdk/blob/master/src/share/classes/java/lang/StringBuffer.java
AbstractStringBuilder has constructor with no args which doesn't allocate the field 'value', which makes accessing the 'value' field being NPE. Any constructors in StringBuffer use that constructor. So maybe some odd thing happens in serialization/deserialization and unfortunately 'value' field in AbstractStringBuilder is being null.
Maybe initializing totalCmds in prepare() would be better, and also you need to consider synchronization (thread-safety) between bolts. prepare() can be called per bolt instance so fields are thread-safe, but class fields are not thread-safe.
I think I find the problem maybe;
the key point is
"StringBuffer _totalCmds = new StringBuffer(totalCmds);" and " totalCmds.append(lastCommands);//line 61"
when new a object, It takes serval steps:
(1) allocate memory and return reference
(2) initialize
if append after (1) and before (2) then the StringBuffer.java extends AbstractStringBuilder.java
/**
* The value is used for character storage.
*/
char[] value;
value is not initialized;so this will get null:
#Override
public synchronized void ensureCapacity(int minimumCapacity) {
if (minimumCapacity > value.length) {
expandCapacity(minimumCapacity);
}
}
this blot has a another question, some data maybe lost under a multithreaded environment