decoupling object construction tied to input data - java

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.

Related

A proper way to make an HashMap with multiple value type

I have an object the represent an entity. By example i have the "user" java object that have the followings field, String name, String first name, String address, boolean deadOrAlive. But now instead of having field i want to put them into a hashmap, so my first reflex was to make it this way :
private HashMap<String, Object> fieldsHM;
This would means that i have to cast my HM value when i want to use it and i don't want to make that because i need to know the type before i use my value. I want to make something like :
Set<String> keys = fieldsHM.keySet();
for(String key : keys) {
if(fieldsHM.get(key).isBoolean()) {
// Do the appropriate things
} else {
// Do the thing for this case...
}
}
I think it's possible in java, would this be good to do it this way ?
EDIT 1: I don't want to make a hashMap because this is not what i need. What i need is a way to browse the fields of the Entity user fields by fields, and depending the type of the field do the appropriate things.
I don't want to make a hashMap because this is not what i need. What i
need is a way to browse the fields of the Entity user fields by
fields, and depending the type of the field do the appropriate things.
I guess that would be a job for Reflection, like User.class.getFields().
It will still be uncomfortable to distinguish between primitive field, but you could use their wrapper classes instead.
But whatever path you choose, I think there would be a better solution if you would state what the actual goal is.
Depending on your actual use case, it might make sense to use JSON (maybe with databind) or even a database.
You could use the heterogeneous container pattern, but I would abandon the map idea and use a proper object.

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.

Using a String as an identifier when creating a new Object

I have a String eg:
1,TSM,501,SM0156,John Thorne,BCO200,24,30,2,CSM,500,AC1157,Peter Jones,BCO104,24,60,...
The string represents a list of people within a department.
The "SM0156" & "AC1157" are their unique identifiers within the department
I would like to loop through the string and create a new 'person object' every time I meet an identifier. The object is then stored in an ArrayList. I believe I could do this with the following code:
deptList.add(new = PersonDetails());
This creates my object but I want to be able to reference it later possibly by the unique identifier! Whilst looping through the original string i have extracted out the identifier in this case "SM0156". I was hoping there was a way to then use this as the reference to the object EG
PersonDetails "SM0156" = new PersonDetails();
deptList.add("SM0156");
Obviously here "SM0156" represents a string but surely I could convert it somehow to use as an reference to my new PersonObject??
Thanks for any help in advance..
You do not want to attempt this. Store your details in a collection and depending on the collection you should use it accordingly.
If you choose an ArrayList, make sure your PersonDetails class has a field Id which you can look up (or create a new class that holds an Id and a PersonDetails object).
Another solution is creating a Map<String, PersonDetails> to map the Id to the person.
Try to use HashMaps. HashMaps stores the objects with key/value principal.
http://www.mkyong.com/java/how-to-use-hashmap-tutorial-java/
You can use a Map<String, PersonDetails>.

How to Simulate Pointer Type Action in Java, or Is Java Pass-By-Reference or Pass-By-Value?

I'm modeling Mysql databases as en exercise in Java. Personal experiment. And I want to store the table collation as a string, since the columns can have different collation then the tables, I need to store that also for each column. It would be very helpful if the column's collation field could just point to the table's collation field. But I know that Java doesn't have pointers.
Do you have an idea on how I can point the field of one object, to he field of another object so the two will always match?
Java has references, which are the good parts of pointers without the ability to do pointer math.
public class Table {
// name does not store a String, it stores a reference to a String
private String name;
// tableName is not passed in by copy, tableName's reference is passed in.
public Table(String tableName) {
// this is not a copy assignment, but a reference assignment
name = tableName;
}
}
As far as always pointing to a field in Java, you must keep in mind a few things. Objects are the basic element in an Object-Oriented programming language, not names. As such, you cannot build a reference to an object's internal names, as it is never clear if you are referencing the Object by its base type or by a super type. Since identical names can exist in both super classes and sub classes (which could then hide the super class type), field name references cannot be correctly resolved without knowledge of the actual class instance they are getting resolved upon.
This is by design, not by accident. In fact, external knowledge of a class's member fields is exactly what makes code maintenance so difficult, as there is no "shim" where one can insert code between the caller and the data. By encapsulating the data (putting in behind a method call) one sets the stage for future code maintenance; because, one can then insert code to generate the return values based on possibly changing internal data elements.
An example
public class Table {
public Column[] columns;
public String name;
public Table() {
name = ...;
columns = ...;
}
}
public class CreateTableDDL {
public String statement(Table table) {
StringBuilder buffer = new StringBuilder();
buffer.append("CREATE TABLE ");
buffer.append(table.name);
buffer.append(" (");
for (int i = 0; i < table.columns.length; i++) {
Column column = table.columns[i];
...
}
...
return buffer.toString();
}
}
exposes columns as an array of type Column, which isn't necessarily a bad thing, until we decide we want it to be a List of Column so we can dynamically add or remove Columns in a new nifty TableEditor.
Since we exposed the base data element, now we must search through the entire code base to find any use of the field, and rewrite all uses to now use a List interface. Actually, we need to do even more than that because we must also search through every external library that might have used the columns field directly, as multiple JARs unknown to us might have used this public class.
In addition, we will quickly notice that most of what we are doing with columns is really the Table's business, but located in "helpers" and auxillary classes which detract from responsibilities best localized in Table.
Finally, we might even notice that external classes are modifying the columns of a table without the table's knowledge; because, they bypass any code that might alert the table to the change by grabbing the data directly.
If we had simply done
public class Table {
private Column[] columns;
private String name;
public Table() {
name = ...;
columns = ...;
}
public Column[] getColumns() {
Column[] copy = new Column[columns.length];
for (int i = 0; i < columns.length; i++) {
copy[i] = columns[i].clone();
}
return copy;
}
}
Then we could have easily converted the base storage to a List and just constructed our "backwards compatible" array of columns from the list. The calling code now doesn't require a change, even if we decide that our previously existing columns field now needs to be a Map of String to DataType.
public class CreateTableDDL {
public String statement(Table table) {
StringBuilder buffer = new StringBuilder();
buffer.append("CREATE TABLE ");
buffer.append(table.getName());
buffer.append(" (");
for (int i = 0; i < table.getColumns().length; i++) {
Column column = table.getColumn(i);
...
}
...
return buffer.toString();
}
}
First some definitions. And keep in mind that the pass by terminology does not refer to the underlying mechanism used to manage data. It refers to what result you can expect the manipulation of that data to give you.
All data is stored in memory locations. How this is defined varies between JVMs, and is not relevant to the discussion.
A pointer is a variable that stores the memory location of a data, instead of the actual data.
A reference is a generic term for any variable that stores some kind of index value that refers to some data. So a pointer is a type of reference. And in this discussion, the only type we care about.
Now in a pass by reference language, the actual data in memory is not being manipulated during assignment. The data is saved in memory. And the reference is assigned a value that tells the computer to go to the memory location to get the actual data. When you assign one variable to another, you assign the same value that tells the computer the data's memory location. So both references index the same data. If you change the actual data, then both references will index the newly changed data. One manipulation can change a number of variables only limited by the capabilities of the computer. A generic code example follows:
a = <valueof 1>; //"1" is now stored in memory, and a is a index to "1" in memory.
b = a; //b now indexes the same memory location as a. They both index the "1" in memory.
a = <value of 2>; //"2" now replaces "1" at the indexed memory location.
output a; //In this case would get the index value the language uses.
output b; //You'd get the same index value as a since they index the same memory location.
output <valueof a>; //Now you get "2", because however it's done in the language you have extracted the data in the memory location indexed by a.
output <valueof b>; //Same output as before as b indexes the same memory location as a.
In a pass by value language, b would still get you 1, and a would now get you 2. This is because b would not have been assigned the same reference as a. It would have been assigned the value as a new reference. The generic code would look the same, but give you different results.
a = <valueof 1>; //"1" is now stored in memory, and a is a index to "1" in memory.
b = a; //b now indexes a new memory location that now also stores "1".
a = <value of 2>; //"2" now replaces "1" at the indexed memory location.
output a; //You get "2" because a pass by value language will be designed to give you value, not the index.
output b; //You get "1" because when b was assigned to match a, a stored "1". But b is independent of a once assignment is complete.
The confusion comes from the fact that Java uses a pass by reference mechanism to achieve a pass by value design, in some cases. In the case of primitives Java acts as pass by value. In the case of Objects, it acts as a pass by reference. And if you wrap a primitive in an object, which is usually recommended, it will act as pas by reference. But while Strings are objects, they also act as pass by value. But Strings are weird.
Java variables are passed by reference. So if you have declared Object obj, then obj will always been a reference to that same object in your current scope. When you pass obj to a method, you're not passing a copy of the object, but a reference to it.
Furthermore, Java also has Iterators for collections that implement the Iterable interface, which you may want to look into. These act like pointers to specific positions within a List or similar.
You create an Enum that has a list of all possible Collation Types, and add a member/property called collationType to the Table and Column classes, and assign the same Enum member to the objects where they are the same.

Array of Strings to an Array of Objects

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.

Categories

Resources