Array of Strings to an Array of Objects - java

Maybe there is a method that does this that I don't know about - I doubt it though - but I'm trying to convert an array of strings to an array of Objects. Here is the problem: I'm reading a file in from the command line. The file represents several classes of the following types each with their own data fields. Vehicle is the parent class of all who follow: Vehicle,Car,American Car, Foreign car, Truck, Bicycle.
I have no problem reading the file into a string array. However I need to create objects of all these types and store them in an array of type Vehicle[]. For example a portion of the file looks like this:
Vehicle
Kim Stanley Robinson
2344 court drive
(221)885-7777
stackoverflow#overflow.com
American Car
John Bunyon
1010 binary lane
(221)885-55643
bgt.com
convertable
made in detroit
union plant
Where Class type is the first line followed by, Owner's Name, address, phone number, email address...Each type has fields particular to it. So a foreign car is not made in Detroit. Each of these fields appear on a separate line in the file. So what I've done is read the entire file into a string array. However, I need to find my types in the array of strings,create objects of those types, and store them in a Vehicle array. My main problem is that each data field is on a separate line. How should I approach this problem?
This is java code by the way.

Initially reading the data into a String array is fine. Then you need to loop through that array, and based on the "first line" of each loop ("Vehicle", "American car" etc) you will know how many subsequent elements of the array belong to the same.
Something like this (i'll let you fill in the blanks yourself):
int i = 0;
ArrayList<vehicle> vehicles = new ArrayList();
while (i < data.length)
{
if (data[i].equalsIgnoreCase("vehicle"))
{
Vehicle vehicle = new Vehicle();
vehicle.setOwner(data[++i]);
...
vehicles.add(vehicle);
}
else if (data[i].equalsIgnoreCase("american car"))
{
...
}
i++;
}

question is unclear. Do you want to know how to parse the file and use the words on each line to create a object of it?
pseudo:
Vehicle_ptr myVeh = null;
for each line in file
switch line
{
case vehicle: myVeh = new Vehicle();
case American Car : myVeh = new AmericanCar();
default:
if (line.startswithaninteger && (myVeh != NULL)) myVeh.address = line;
etcetc.
}
Tips: use typeidentifiers in the textfile.for example:
car:americancar
address:12345 bla
etcetc
Or use a serializer

You could read the file as you are doing just now but when you read a string that is a Class type create an instance of the correct Vehicle type. It would appear that you would then know that the next x lines of the file are properties of that particular type so you would read the properties and set them on your Vehicle instance. You then have your Vehicle instance to add to the Vehicle array.

I would use a Factory pattern that creates Adapters. The factory would take the string (Vehicle, American Car) and the adapter would take the string array and current index. The adapter would be responsible to knowing how many indices to read and return the concrete object (or an interface).
IAdapter adapter = AdapterFactory.Create( "American Car" );
Object concreteObject = adapter.Popluate( stringArray, currentIndex );
Now, if you have control over how the data is stored, you might want to look into standard serialization, even JSON, to make processing easier.

It seems to me you need a factory pattern to build your set of vehicle types from the inputs. The factory can look after determining where one car specification starts and another one ends. It'll then determine the set of fields for a car, and determine the car type. It can then call the appropriate constructor, passing in all the related fields.
This means that a constructor of (say) an American car specifies all the fields that it's interested in. A European car constructor would do the same. Each constructor can assert on what it's been given so you don't create any cars incorrectly.
The factory will look after parsing and separating the inputs, and determining what is to be built. Each type of car's constructor looks after info for that car only, and performs the appropriate asserts.
The factory will maintain the list of cars created, and return that list (of America/European/Japanese) upon completion.
In pseudo-code:
whilst(!done) {
fields.add(fieldFromFile);
if (carSpecificationCompleted) {
type = getType(fields);
if (type == 'American') {
car = new AmericanCar(fields);
}
else if (type == 'European') {
car = new EuropeanCar(fields);
}
cars.add(car);
clearStoredFields();
}
}

Do you have control of the file being passed in? If so, might I suggest formatting it using XML and then parsing it using JDOM? It would make your life easier in terms of parsing. For example, you could format all vehicle entries like this:
<node type="vehicle>
<attributes location="detroit" color="red" />
</node>
Or whatever format you come up with. The benefit of this is you can then read in only the vehicles (or whatever you want), or use XPath or some other technology to efficiently get the info you want/need and load it to the proper datatype.
Disregard this advice if you have no control over file formatting.

When you have the choice, change your file format.
You can serialize your object by using xstream. Then you only have to store the complete Java object without checking if some value is existing.

I'd use the Builder pattern here instead of Factory. No big difference but find it a bit easier when the parameters vary like it seems to do in his example.

Related

decoupling object construction tied to input data

What I'm doing
I'm using Dependency Injection to decouple my classes.
How I'm trying to do it
The class I am making constructs ObjectImplementation (the interface) Objects to hold data and it acts as a sort of container. I'm doing this to parse data and cross reference two data-sets. My problem is that I currently have object construction tied to the data being formatted a certain way. I am using the Factory pattern and a properties file "config.properties".
What I want to be able to do
I want to be able to have the factory take in an array of fields or some other similar type and be able to construct instances of the reflected object type without dependencies on the data. In this case they are Salesrep instances but other times I want to construct Salesrep instances or other classtype instances with different fields filled and different ones null without formatting the data to contain the names of fields.
The end goal
The point is so that I can construct different objects with the same container code. If I want to contain the objects differently I'll simply make a new implementation of the parent interface of this container class.
What I'm thinking is the problem
I've figured out that a Fieldmap was a good idea through previous versions of this question and my own research. Yet there is no way to actually set those fields without having something in the data to match to the Fieldmap
Extra Clarification
I really want to know if I can find a way to achieve my goal without adding field names to the data
//creates new properties object and loads in the file configuration
Properties prop = new Properties();
prop.load(SalesRepbyId.class.getResourceAsStream("config.properties"));
//reflects in the class we wish to use
Class<? extends ObjectImplementation> Classtouse = Class.forName(prop.getProperty("ObjectImplementation")).asSubclass(ObjectImplementation.class);
//initializes the data and some hashmaps to store the data or the methods of the reflected class
ArrayList<String[]> Salesrep_contactlist = FileParser.ReadFile();
Map<String, ObjectImplementation> SalesrepByIdMap = new HashMap<>();
Map<String, Method> MethodMap = new HashMap<>();
//adds in the data (fields) by constructing objects of the reflected type using the ObjectImplementation interface
for (String[] fieldarray : Salesrep_contactlist) {
ObjectImplementation object_to_add = null;
try {
//utilizes the factory pattern to return an instance of the reflected class
object_to_add = Factory.getObjectImpl(prop.getProperty("ObjectImplementation"),fieldarray);
/**
uses a method hashmap to map the name of the method to the Method object.
I did it this way because dynamic variable declarations are not possible and
I wanted to decouple Method declarations from the specific class that has
them. If i just hardcoded in which methods I get from the implementing class
that introduces extra dependencies I don't want.
**/
for (Method method:Classtouse.getMethods()) {
MethodMap.put(method.getName(),method);
}
//same as above but for fields this time
for (Field field:Classtouse.getFields()) {
FieldMap.put(field.getName(),field);
}
//object_to_add is a String[] with the format [Fieldname1:fieldinput1,Fieldname2:Fieldinput2]
//so I want to get this array and get each element, seperate the fieldname and then use that string to access the actual Field object of the same name in FieldMap
String fieldname = object_to_add.get(0).split(":").get(0)
String fieldinput = object_to_add.get(0).split(":").get(1)
Field name_example = Fieldmap.get(fieldname)
name_example.set(String.class,fieldinput)
//This requires the data to have the fieldname in it rather than just the fieldinput (or data). Also it confines the input to be strings because I don't think I can use a generic type to set this field even though potentially I would want to.
There is no way for me to dynamically set Field types without something to go off of in the data or elsewhere. In order to avoid something hard coded like: Salesrep rep = new rep (arg1,arg2,arg3 ...) I needed to use the Fieldmap and be able to match the data coming in to what fields I wanted to set. Since I didn't want to do it by order ex:
List list = new list("bob","800-352-4324","foo#example.com");
int i = 0;
for(i = 0, i > list.size(), i++){
Field field = new Field(//need a name here automatically rather than hardcoded)
field.set(object_to_add,list[i])
i++
}
The above didn't have any reference to the actual name of the Field that I actually use in my class. I didn't want that and then it dawned on me that the first line of my data (which is in CSV format) has the Field names effectively listed. ex:
(in the CSV File) foo.txt:
1: name,phonenumber,email
2: "bob","800-352-4324","foo#example.com"
3: "steve","800-444-4444","annoyingcommercials#example.com"
4: ...
Using this knowledge My solution is to use the first line of my data to specify the field names and their order so that when I take in lines as an array of these strings I can use the first line array as a reference to how to set the fields. I will know that the first element in the array should be the name the second should be the number ect ect. This way I only have to change the first line if I want to change how many fields the data holding class actually has.
puesdocode:
ObjectImpl. Classtouse = refelct in the class to use here from properties file
List(String[]) fieldarray = the raw data taken in and converted to a list of string arrays
String[] firstline = fieldarray.getfirstline()
List(String[]) restoflines = fieldarray.getallotherlines()
for i = 0, i > firstline.size(), i++{
Fieldmap.put(Name of the field from firstline[i], create a new Field object here with the Name);
Field fieldtoset = Fieldmap.get(Name of the field again)
fieldtoset.set(make an instance of the Classtouse here, restoflines[i] which represents the data in the 'Name' column)
}
For some silly reason I had it in my head that there was a way to do this without any change to the data, as if the Factory which created the object could take in arbitrary/generic arguments and somehow just know where each field went. I realized that that was silly because I needed to tell the code how to actually set the fields but In a way that it wasn't hard-coded into the class. This solution puts the dependency on the data so now its not hard-coded into the class. I should have seen this sooner.

Object Array to TextArea

I have an array of objects and i want to print them out to a TextArea in a JavaFX program. Im not sure how to go about doing that. Everything that im try doesnt work.
for(int i = 0; i < set.getEngCourse().length; i++){
txt.append(set.getEngCourse()[i]);
if(i != set.getEngCourse().length -1){
txt.append("\n");
}
taken = new TextArea(txt.toString());
The object im trying to get onto the TextArea is a couple of course objects.
There are some assumptions to be made, since not all of the code is posted. We will assume that set.getEngCourse() properly returns an array of some Object, and that set cannot be null, and that .getEngCourse() returns at a minimum an empty array and not a null if there are no courses (if either of these assumptions can be violated, add appropriate null checks). It would be best if the returned array were of some specific type (e.g., EngCourse), but the OP code does not make clear what is in the array.
I would approach the solution in a manner similar to the following:
StringBuilder txt = new StringBuilder(); // get something to collect the output
for (Object obj : set.getEngCourse) { // If possible, change Object to the specific type
// add a line break if we have already added something,
if (txt.length() > 0) {
txt.append("\n");
}
txt.append(String.valueOf(obj)); // will handle null objects
}
taken = new TextArea(txt.toString()); // assumes taken is declared elsewhere
If there is a known object type, it would be better to:
Override the .toString() on the object type
Use the specific object type in the iteration
for (EngCourse ec : set.getEngCourse()) { //use specific type
...
txt.append(ec.toString()); //technically, the .toString() is not needed
}
Also, if the .getEngCourse() returns multiple objects, I would recommend changing the name to .getEngCourses() to make clear that it is returning N courses, and not just a single course.
If a TextArea is not strictly required, I would also consider using a JList or something similar. Basically, dumping everything in to a TextArea simply gives output, without much ability to do anything else with it (such as select a particular course for future operations). Consider, e.g., this SO answer Java JList model. In essence model the domain using appropriate classes, and then use a model/view/controller approach to display the domain classes rather than thinking of the domain as essentially String objects.
Is your txt object a string? If so then why are you putting a txt.toString in the last line of your snippet?
You can use setText function to display the contents in your text area.
Post the error or problem more specifically and extend your code snippet for us to know the scope of for loop.

Adding External Properties to an Object

Noob Java question here. I am wondering if there is a standard way to add additional/external properties to a POJO. i.e., say I have a User Object that I add to an ArrayList in my program. This Object will contain things like first name, last name, address, email, phone, etc., corresponding to whatever is defined in my database.
Now say that I have the requirement to include external attributes along with said User, such as Employer ID, Vehicle Plate #, Smartphone type. I will need to be able to include these extra properties when adding a User to my ArrayList - Is it possible to attach these strictly with Java so that I can have acces to them?
I've thought of going with something like a Value Object, in where the VO would include all the User Properties along with the extra fields to be added from outside Classes, but want to explore more possibilities. Any ideas? Thanks much
You have many possibilities. Here are a few that immediately spring to mind:
Refactor the User class. This is the obvious one, so I presume you have a good reason for not doing so.
Write a class that extends User, containing this information. Presuming you're only storing this information for a subset of the users that this information applies to, this makes the most sense.
Use composition - create a new class that holds a user instance and then any other information you want to add to it.
One big influence on what design you use will be whether all additional values are unique, or if a User can have multiple smartphones, vehicles, etc.
If all additional fields are all unique you can just slide in java.util.Properties (or other Maps). Your User class needs at least
import java.util.Properties;
class User
{
Properties extra_attr = new Properties();
// ... existing code ...
public void setExtraAttr(String field, String value) {
extra_attr.setProperty(field,value);
}
public String getExtraAttr(String field) {
return extra_attr.getProperty(field);
}
}
Then use calls like some_user.setExtraAttr("Employer ID","314159"); and some_user.getExtraAttr("Employer ID"); to set and get your extra attributes.
If you need multiplicity you may need a different approach, or you can just code over your implementation of Properties. For instance, you can rewrite setExtraAttr() to look for existing keys and add an index
public void setExtraAttr(String field, String value) {
if(extra_attr.getProperty(field) == null)
extra_attr.setProperty(field,value);
else {
int index = 1;
while(extra_attr.getProperty(field+index) != null)
index++;
extra_attr.setProperty(field+index,value);
}
}
You then need some kind of loop where ever you get attributes to look for and handle the multiple extra records.

How to store multiple fields of different datatypes in any 2D array in java?

I want to store three values in a 2D type in java. I know that we can use List and ArrayList for storing 1D values but I need to store more than one field in a specific record. For example i have to enter the details for multiple columns i.e. (1,1),(1,2),(1,3) for details such aaaa, bbbb, cccc for a person and store them in one single row(which may consist of values which are other than string type). It should run in a loop and once details of a person is stored, it should store (2,1),(2,2),(2,3) i.e. again for a new person. How to do that?
And later on, how to retrieve and send the complete set to database together? Please help..
What you might want to do is to create a class that holds all of the information you want to keep related to a single record if it represents a concrete thing and use the List and ArrayList to store those.
What I mean by concrete thing is something that has a finite set of information that will stay the same over each object.
Something like:
public class Person
{
String name;
Integer age;
// etc...
}
This gives you two advantages over using something like a 2D array. First, it will make reading your code easier, since instead of having to remember that arrayName[x][0] is whatever you decide the first field is, you can access it using something like listItem.attributeName. The second advantage is that you can abstract out any common datahandling tasks as class methods instead of having to bloat your main class with it.

Java Dynamic Memory Allocation (Heap)

This isn't a question that I am expecting a specific answer to since it is pretty broad. I'm teaching myself Java and am focusing specifically on dynamic memory allocation. Let's make a very oversimplified example: Say that I have a really basic data entry screen. So basic that all that happens is the user enters a series of first names, maybe for an employee directory or something. On my JFrame, I have a single JTextField control where these names are entered. The number of employees is known only at run time. The user enters a name and hits the enter key, which commits the name to memory and creates a new object to store the next name (silly, I know, but I'm trying to focus). Something like this (don't take this too literally - I obviously didn't compile this):
public class Employee {
String fName;
public void setName( String n ) {
fName = n;
}
};
public class JFrameEmp {
//blah, blah, blah
JTxtName.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e) {
/* Handle the enter key */
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
/* Store name */
this.setName(JTxtName.getText());
/* Create New Object */
Employee next = new Employee();
}
};
}
}
Where I need help is on the last line. Even if this were to work, let's say that I wanted to print out a list of the names entered. In my approach, I see no way to uniquely identify each object (so that I can iterate through them).
Do I need to create an array to store these? But that has a fixed length and lives on the stack. I'd rather find a way to use the heap to allow for an open-ended list.
What should I be reading to learn how to do this? It must be a very common thing to do, but the books that I have don't seem to cover it.
Thanks. I hope that I have explained this well enough without going into too much detail.
It sounds like you want to store a List of Employees. Java provides dynamically sized array with its ArrayList class.
Here is an example:
ArrayList<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee("Alice"));
employees.add(new Employee("Bob"));
System.out.println(employees.get(0)); // prints out Alice
You could use an array. You might find it useful to have a look at the Java Collections framework, in particular the page about the implementations.
But yes you will need to be adding the objects to some sort of data structure otherwise they will be getting cleaned up by the garbage collector after there is no valid reference to them.
It seems like you are looking for a data storage structure.
You could use a built in array, which is actually stored on the heap in java(the only issue is that you would have to keep track of size and reallocate when more space is needed).
A better option would be an ArrayList, which has built in add methods that automatically resize when needed.
You could also use a HashMap, which would allow to quickly search for your employees by name.

Categories

Resources