List stores the last added value only - java

I have a problem with the following code:
First of all i have an inner class:
public class TraceMessage{
private String messageType;
private String tracedIdentifier;
private List<String> content;
TraceMessage(){
content = new ArrayList<String>();
messageType="";
tracedIdentifier="";
}
TraceMessage(String messageType, String identifier ,List<String> content){
this.messageType = messageType;
this.tracedIdentifier = identifier;
this.content = content;
}
It has getters and setter for the 3 attribute. My problem is:
I have a list of this messages:
private List<TraceMessage> messages = new ArrayList<TraceMessage>();
and I'm trying to add new elements to this like that:
messages.add(new TraceMessage(temp.messageType,temp.tracedIdentifier,temp.content));
where temp is an TraceMessage object.
So My problem when i add a message type object like that to the List the values are fine I even put printout to the Constructor and it has also shows the good value. But later When I'm trying to use that List all elements of the list has the same content(the last one). What could be the problem?
Here is the full part where i add the messages:
String fileName="tracefile.MTR";
BufferedReader br = new BufferedReader(new FileReader(fileName));
try {
String line;
TraceMessage temp = new TraceMessage();
while ((line=br.readLine()) != null) {
if(line.contains("MSCi")){
temp.content.clear();
temp.content.add(line);
}
else if(line.contains("CALL PHASE")){
temp.messageType = line.substring(60);
temp.content.add(line);
}
else if(line.contains("CALL ID")){
temp.tracedIdentifier = line.substring(22);
temp.content.add(line);
}
else if(line.contains("END OF REPORT")){
temp.content.add(line);
messages.add(new TraceMessage(temp.messageType,temp.tracedIdentifier,temp.content));
}
else{
temp.content.add(line);
}
}
} finally {
br.close();
}

I would rewrite the second constructor to take copy of list
TraceMessage(String messageType, String identifier ,List<String> content){
this.messageType = messageType;
this.tracedIdentifier = identifier;
this.content = new ArrayList<String>(content);
}
This will copy temp.content that you are reusing in while loop. Instances will be safe from operations on contents collection executed outside of the class.

put TraceMessage temp = new TraceMessage();
inside the while loop
and change messages.add(new TraceMessage(temp.messageType,temp.tracedIdentifier,temp.content));
to
messages.add(temp);
Ok if you can't do that
replace messages.add(new TraceMessage(temp.messageType,temp.tracedIdentifier,temp.content));
with
messages.add(temp); messages = new TraceMessage();

Change your code like this:
...
try {
String line;
List<String> content = new ArrayList<String>();
String messageType = "";
String tracedIdentifier = "";
while ((line=br.readLine()) != null) {
if (line.contains("MSCi")){
content.clear();
content.add(line);
}
else if (line.contains("CALL PHASE")) {
messageType = line.substring(60);
content.add(line);
}
else if (line.contains("CALL ID")) {
tracedIdentifier = line.substring(22);
content.add(line);
}
else if (line.contains("END OF REPORT")) {
content.add(line);
messages.add(new TraceMessage(messageType, tracedIdentifier, content);
}
else {
content.add(line);
}
}
} finally {
br.close();
}
Instead of using a temp object, save your attributes in external variables (out of the while loop) and then add a new object to your messages list with those variables.

Related

Java method to read text file and return ArrayList type object

public static void main(String[] args)
{
ArrayList <Locations> LocationsList = readFile("Locations.csv", "Locations");
//ArrayList <Movies> MoviesList = readFile("Movies.csv", "Movies");
//ArrayList <Operators> OperatorsList = readFile("Operators.csv", "Operators");
//ArrayList <PersonCategory> PersonCategoryList = readFile("PersonCategory.csv", "PersonCategory");
}
public static ArrayList readFile(String fileName, String whichFile)
{
ArrayList list = new ArrayList();
try
{
BufferedReader br = new BufferedReader(new FileReader(fileName));
String indata;
int line = 0;
while((indata=br.readLine())!=null)
{
StringTokenizer st = new StringTokenizer(indata,",");
if(line != 0)
{
if(whichFile.equals("Locations"))
{
int id = Integer.parseInt(st.nextToken());
String city = st.nextToken();
if(city.charAt(0) == '"')
{
String c = st.nextToken();
city = city.substring(1,city.length()) +"," +c.substring(0,c.length()-1);
}
int stateId = Integer.parseInt(st.nextToken());
Locations x = new Locations(id, city, stateId);
list.add(x);
}
else if(whichFile.equals("Movies"))
{
int id = Integer.parseInt(st.nextToken());
String name = st.nextToken();
int ratingId = Integer.parseInt(st.nextToken());
Movies x = new Movies(id, name, ratingId);
list.add(x);
}
}
line++;
}
br.close();
}
catch (FileNotFoundException fnfe){System.out.println(fnfe.getMessage());}
catch (IOException io){System.out.println(io.getMessage());}
catch (Exception e){System.out.println(e.getMessage());}
return list;
}
I'm trying to create a method that will read a text file and can return an ArrayList type object for the usage of multiple Class. With my code above, it can run successfully.
But, there are lines of warning like:
"The expression of type ArrayList needs unchecked conversion to conform to ArrayList<Locations>"
How do I fix this?
Try this.
public static <T> ArrayList<T> readFile(String fileName, Function<String[], T> converter) throws IOException {
ArrayList<T> result = new ArrayList<>();
try (BufferedReader reader = Files.newBufferedReader(Paths.get(fileName))) {
String line = reader.readLine();
String[] fields = line.split(",");
T object = converter.apply(fields);
result.add(object);
}
return result;
}
and define the converters which convert a CSV line to an object.
static Locations convertLocations(String[] fields) {
int id = Integer.parseInt(fields[0]);
String city = fields[1];
if (city.charAt(0) == '"') {
String c = fields[2];
city = city.substring(1, city.length()) + "," + c.substring(0, c.length() - 1);
}
int stateId = Integer.parseInt(fields[3]);
Locations x = new Locations(id, city, stateId);
return x;
}
static Movies convertMovies(String[] fields) {
/* Make Movies object from fields */
}
and combine them.
ArrayList<Locations> LocationsList = readFile("Locations.csv", fields -> convertLocations(fields));
ArrayList<Movies> MoviesList = readFile("Movies.csv", fields -> convertMovies(fields));
You need to create the proper generics-based ArrayList using for example: new ArrayList<Location>()
You could solve this by passing a class to readFile like this:
public static <T> ArrayList<T> readFile(....., Class<T> clazz)
{
ArrayList<T> list = new ArrayList<T>();
...
}
This is my final code that I took from #saka1029 and made some adjustments so that it will read every line in the file except the first one.
public static <T> ArrayList<T> readFile(String fileName, Function<String[], T> converter)
{
ArrayList <T> list = new ArrayList<>();
try
{
BufferedReader br = new BufferedReader(new FileReader(fileName));
br.readLine();
String inData;
while((inData=br.readLine()) != null)
{
String[] fields = inData.split(",");
T object = converter.apply(fields);
list.add(object);
}
br.close();
}
catch (FileNotFoundException fnfe){System.out.println(fnfe.getMessage());}
catch (IOException io){System.out.println(io.getMessage());}
catch (Exception e){System.out.println(e.getMessage());}
return list;
}
And this is my version of the correction of the method convertLocations from #saka1029 answer.
static Locations convertLocations(String[] fields)
{
int id = Integer.parseInt(fields[0]);
String city = fields[1];
int stateId;
if (city.charAt(0) == '"')
{
String c = fields[2];
city = city.substring(1, city.length()) + "," + c.substring(0, c.length() - 1);
stateId = Integer.parseInt(fields[3]);
}
else
stateId = Integer.parseInt(fields[2]);
Locations x = new Locations(id, city, stateId);
return x;
}
Essentially, you need to specify the type parameter for generic class ArrayList.
Since you are adding objects created from different classes to the same list, you could create an interface, say, MyInterface
public interface MyInterface {
....
}
All classes you return from readFile must implement this interface. For eg.
public class Movies implements MyInterface {
....
}
Now, you can add type parameter MyInterface at appropriate places:
public static void main(String[] args) {
ArrayList<MyInterface> LocationsList = readFile("Locations.csv", "Locations");
....
}
public static ArrayList<MyInterface> readFile(String fileName, String whichFile) {
ArrayList<MyInterface> list = new ArrayList<>();
....
}
Added below info based on reply
You may in fact choose to leave the interface blank, but then you will have to explicitly cast objects to concrete classes to do anything useful.
You could cast each object when needed
MyInterface myInterfaceObject = locationsList.get(0)
Locations locations = Locations.class.cast(myInterfaceObject);
OR
MyInterface myInterfaceObject = locationsList.get(0)
Locations locations = (Locations) myInterfaceObject;
OR You could write a list converter function for each concrete type
public class ListConverter {
public ArrayList<Locations> toLocationsArraylist(ArrayList<MyInterface> inList) {
ArrayList<Locations> outList = new ArrayList<>();
for (MyInterface listItem : inList) {
outList.add((Locations) listItem);
}
return outList;
}
}
and then
public static void main(String[] args) {
ArrayList<MyInterface> myInterfaceList = readFile("Locations.csv", "Locations");
ArrayList<Locations> locationList = ListConverter.toLocationsArraylist(myInterfaceList);
}
If you do consider using this solution, then consider renaming MyInterface more appropriately, say, to CsvRecord, or anything domain-specific.

Why is my Java Program returning only the last String in an ArrayList

I want my Java Program to return a String response based on if/else conditions but it only responds to the last element in the ArrayList.
I have been working on this for two days without success.
I will appreciate a direction as to what am doing wrongly. Thank You
import java.io.IOException;
import java.util.logging.Logger;
public class ScanUtility implements IScanUtility {
Logger logger = Logger.getLogger("ScanUtility");
private String performHostScan(String nodeName) {
Process OSCmdProcess = null;
Integer exitValue = null;
String OScmd = null;
String exitMessage = null;
String OScmd = new String("/usr/bin/ssh ansible#" + nodeName + " " + "/tmp/openscapscan.bash rheldisa");
try {
OSCmdProcess = Runtime.getRuntime().exec(OScmd);
exitValue = OSCmdProcess.waitFor();
if (exitValue.equals(0)) {
exitMessage = ("Succeeded on" + " " + nodeName);
return exitMessage;
} else {
exitMessage = ("Failed on" + " " + nodeName);
return exitMessage;
}
} catch (IOException ioExcep) {
ioExcep.printStackTrace();
} catch (InterruptedException interExcep) {
interExcep.printStackTrace();
}
return exitMessage;
}
//This method takes an ArrayList of hosts from the servlet controller
// and passes the list to the ScanUtility Method above
//============================================================
public String generateHostName(List<String> addressList){
String statusMessage = null;
for(String nodeName: addressList){
statusMessage = new ScanUtility().performHostScan(nodeName);
}
return statusMessage;
}
}
The problem is that you are overwriting statusMessage on ever iteration of your loop. I believe what you want to do is put all the Strings into an ArrayList<String>.
public ArrayList<String> generateHostName(List<String> addressList){
ArrayList<String> statusMessage = new ArrayList<>();
for(String nodeName: addressList){
statusMessage.add(new ScanUtility().performHostScan(nodeName));
}
return statusMessage;
}
Apparently, you want to return a list of status messages (a status message from each server that you are scanning).
public List<String> getResponsesFromAddresses(List<String> addresses) {
final ScanUtility scanUtility = new ScanUtility();
return addresses.stream()
.map(scanUtility::performHostScan)
.collect(Collectors.toList());
}
The method name is misleading. I have changed it to getResponsesFromAddresses - that is what the method actually does.
Try this:
public List<String> generateHostName(List<String> addressList){
List<String> statusMessages = new ArrayList<>();
for(String nodeName: addressList){
statusMessages.add(new ScanUtility().performHostScan(nodeName));
}
return statusMessages;
}

Separating Parsing Method

I'm creating a program which handles SKU's. I currently have two classes in my program, the SKU class is the main class and a Store class in which an ArrayList is initialised and SKU objects are stored in the array. I currently have a method in my SKU class which takes input from a file, parses the data and stores the data using a String tokenizer in the objects variables and adds the objects to the array in the Store class. The problem I'm facing is that I'm wanting to separate the parsing method in the SKU class so that it simply reads from a line, and then have a separate method which takes a file input for the parser and finally update my Store class so that it initialises the products with the parsed data. Please, can you help me in regards to this?
My parsing method in the SKU class is currently as follows:
public void parser() {
try {
// create a Buffered Reader object instance with a FileReader
BufferedReader br = new BufferedReader(new FileReader("products.txt"));
// read from first line from the text file
String fileRead = br.readLine();
// skip first line from sample file as it contains headings
int lineNumber = 0;
// loop until all lines are read
while (fileRead != null)
{
if(lineNumber == 0) {
lineNumber++;
continue;
}
lineNumber++;
// use string.split to load a string array with the values from each line of
// the file, using a tab as the delimiter
String[] tokenize = fileRead.split("\t");
// assume file is made correctly
// and make temporary variables for the three types of data
String tempProductCode = tokenize[0];
String tempDescription = tokenize[1];
BigDecimal tempPrice = new BigDecimal(tokenize[2]);
// create temporary instance of SKU object
// and load with three data values
SKU tempObj = new SKU();
tempObj.setProductCode(tempProductCode);
tempObj.setDescription(tempDescription);
tempObj.setPrice(tempPrice);
// add to array list
Store.mySkuArrayList.add(tempObj);
// read next line before looping
// if end of file reached
fileRead = br.readLine();
}
// close file stream
br.close();
}
// handle exceptions
catch (FileNotFoundException fnfe)
{
System.out.println("file not found");
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
My Store class is as follows:
public class Store {
public static ArrayList<SKU> mySkuArrayList = new ArrayList<SKU>();
public void addSKU(SKU sku) {
mySkuArrayList.add(sku);
}
Split your code to three separate classes. SkuFile class represents text file where sku codes is stored, this class knows how to every sku entry stored and able to parse it. Sku class contains data. Store class contains
list of Sku and accept SkuFile in it's constructor.
class SkuFile {
private String path;
SkuFile(String path) {
this.path = path;
}
List<Sku> readAllSku() {
ArrayList<Sku> result = new ArrayList<>();
try {
List<String> lines = Files.readAllLines(new File(path).toPath());
for(String skuLine : lines) {
result.add(parseFrom(skuLine));
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return result;
}
private Sku parseFrom(String data){
String[] tokenize = data.split("\t");
productCode = tokenize[0];
description = tokenize[1];
price = new BigDecimal(tokenize[2]);
return new Sku(productCode, description, price);
}
}
class Sku {
private String code;
private String description;
private BigDecimal price;
Sku(String code, String description, BigDecimal price) {
this.code = code;
this.description = description;
this.price = price;
}
//getters setters methods
}
class Store {
private List<Sku> skus;
Store(SkuFile file) {
skus = file.readAllSku();
}
}
class Test {
public static void main(String[] args) {
Store store = new Store(new SkuFile("products.txt"));
}
}
One way to handle this is by making the parse method return a list of tokenizers(e.g. List tokenizeList) and a second method which takes that list as input and populates the SkuArrayList
Possible implementation of the parser method
public List<String[]> parser() {
List<String[]> tokenizeList = new ArrayList<>();
try {
... /*file opening logic*/
while (fileRead != null)
{
.../*line counting logic*/
String[] tokenize = fileRead.split("\t");
tokenizeList.add(tokenize);
fileRead = br.readLine();
}
// close file stream
br.close();
}// handle exceptions
catch (FileNotFoundException fnfe)
{
System.out.println("file not found");
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
return tokenizeList;
}
Possible implementation of the populate store method
public void populateStore(List<String[]> tokenizeList) {
for(String[] tokenize: tokenizeList) {
String tempProductCode = tokenize[0];
String tempDescription = tokenize[1];
BigDecimal tempPrice = new BigDecimal(tokenize[2]);
SKU tempObj = new SKU();
tempObj.setProductCode(tempProductCode);
tempObj.setDescription(tempDescription);
tempObj.setPrice(tempPrice);
// add to array list
Store.mySkuArrayList.add(tempObj);
}
}
And the main method from where you call these two methods
public void foo() {
populateStore(parser());
}

Why does this REST-service not return while the other does?

SITUATION
In the code below you can see 2 REST services which both should return a MessageVO. The first service (serviceThatDoesWork) returns a MessageVO as excpected, but the second service (serviceThatDoesNotWork) refuses to, it doesn't even give any output at all.
However returning a Response (java.ws.rs.core.Response) with serviceThatDoesNotWork does give an output. Even when I skip the 'doStuff'-methods and create a dummy-MessageVO that is exactly the same for each service, the 2nd one doesn't return anything.
QUESTION
Why does the 2nd service fail to return a MessageVO? It doens't return anything when I try returning a MessageVO, and nothing out of the ordinary appears in the logging.
The two services need to return exactly the same kind of thing but still one of them doesn't want to return anything, what am I not seeing here?
Could it be because of the path (and/or the amount of parameters)?
CODE
MyServices.java:
#Path("/myService")
...
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/myPath/{param1}/{param2}/{param3}")
public MessageVO serviceThatDoesWork(#PathParam("param1") Integer param1_id, #PathParam("param2") Integer param2_id, #PathParam("param2") Integer param2_id)
{
List<SomethingVO> lstO = MyRestServiceBusiness.doStuff(param1_id, param2_id, param3_id);
//return SUCCESS or FAIL message
MessageVO msg = new MessageVO();
if(lstO.size() > 0)
{
List<String> s = new ArrayList<String>();
for(SomethingVO k : lstO)
{
s.add(k.getId().toString());
}
msg.setItem_ids(s);
msg.setMsg("SUCCESS");
}
else
{
msg.setMsg("FAIL");
}
return msg;
}
...
#GET
#Path("/myPath/{param1}/{param2}/{param3}/{param4}/.../{param15}{a:(/a/[^/]+?)?}{b:(/b/[^/]+?)?}")
public Response serviceThatDoesNotWork(#PathParam("param1")Integer param1_id, ..., #PathParam("param15") Integer param15_id,
#PathParam("a") String a_id, #PathParam("b") String b_id)
{
//PUT 'OPTIONAL' PARAMS IN A LIST
List<Integer> lstI = new ArrayList<Integer>();
String aId = a_id != null ? a_id.split("/")[2] : null;
String bId = b_id != null ? b_id.split("/")[2] : null;
if(aId != null)
{
lstI.add(Integer.parseInt(aId ));
}
if(bId != null)
{
lstI.add(Integer.parseInt(bId ));
}
//DO STUFF
String afsId = "";
if(lstI.size() > 0)
{
afsId = MyRestServiceBusiness.doStuff(param1, ..., lstI);
}
//return SUCCESS or FAIL message
MessageVO msg = new MessageVO();
if(afsId != null && !afsId.isEmpty())
{
List<String> s = new ArrayList<String>();
s.add(afsId);
msg.setItem_ids(s);
msg.setMsg("SUCCESS");
}
else
{
List<String> s = new ArrayList<String>();
for(Integer i : lstI)
{
s.add(i.toString());
}
msg.setItem_ids(s);
msg.setMsg("FAIL");
}
//WENT THROUGH ALL ABOVE CODE AS EXPECTED, MESSAGEVO HAS BEEN FILLED PROPERLY
return msg;
}
CODE MessageVO.java:
#XmlRootElement
public class MessageVO
{
private String msg;
private List<String> item_ids;
//GETTERS
#XmlElement(name = "Message")
public String getMsg() {
return msg;
}
#XmlElement(name = "Item ID's")
public List<String> getItem_ids() {
return item_ids;
}
//SETTERS
public void setMsg(String msg) {
this.msg = msg;
}
public void setItem_ids(List<String> item_ids) {
this.item_ids = item_ids;
}
If I need to provide extra information please ask, this is my first attempt at (REST-) services.
As Vaseph mentioned in a comment I just forgot the #Produces annotation in the 2nd service.

Populate a JComboBox with an ArrayList from a different class

I'm currently stuck in this part of a class project... I need to create an ArrayList from a text file; text file has account numbers that need to be populated in a JComboBox. This is what I have so far... only the first account number populates missing the rest not sure what my mistake is
// AccountUtility class that reads file and creates ArrayList named test
public class AccountUtility {
ArrayList<String> test = new ArrayList<String>();
String[] number;
String columns[], accountNumber, customerName, openDate, balance;
int size;
public AccountUtility(){
BufferedReader in = null;
try{ // assume products.txt already exists
in = new BufferedReader(new FileReader("accounts.txt"));
String line = in.readLine();
while(line != null) {
columns = line.split("<>");
accountNumber = columns[0];
customerName = columns[1];
openDate = columns[2];
balance = columns[3];
line = in.readLine();
}
in.close();
}
catch(IOException ioe)
{
System.out.println(ioe);
}
}
public ArrayList <String> getAccountNumbers( ){
ArrayList <String> test = new ArrayList<String>();
test.add(accountNumber);
return test;
//class with JComboBox (GUI)
public class BankAccountApp extends javax.swing.JFrame {
public BankAccountApp() {
initComponents();
setLocationRelativeTo(null);
AccountUtility gc = new AccountUtility();
for( String numbers : gc.getAccountNumbers()){
accountNumberComboBox.addItem(numbers);
}
}
I would have thought that what you want is
while(line != null) {
columns = line.split("<>");
accountNumber = columns[0];
test.add(accountNumber);
....
}
and
public ArrayList getAccountNumbers( ){
return test;
}

Categories