Navigation through Objects in Java - java

My aim is to recreate the structure of XML in custom Objects to operate with it further. Actually, I want to have XML as input and produce LaTeX as output. For this task I have implemented principles of JAXB library. But don't think that this is a good idea, because it is not convenient to retain the needed structure of document as output in TeX.
Here is an example of my custom class:
public class Section {
private String title;
private List<Par> par;
private List<SubSec> subsec;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = "\\section {" + title + "}";
}
public List<Par> getPar() {
if (par == null) {
par = new ArrayList<Par>();
}
return this.par;
}
public List<SubSec> getSubSec() {
if (subsec == null) {
subsec = new ArrayList<SubSec> ();
}
return this.subsec;
}
}
So I have a list of Section class, which have titles, list of paragraphs (Par) and list of subsections (SubSec) (simplify LaTeX article structure). Paragraphs contain text, but subsection can include also list of paragraphs.
After XML input I transfer all Data from it in objects, instances of this Classes.
As example:
List<Section> listSections = new ArrayList<Section>();
// omitting the actions to recreate the structure and set values to Objects
// now, to retrieve and write:
for (int j = 0; j < listSections.size(); j++) {
List<Par> listParText = listSections.get(j).getPar();
writer.write(listSections.get(j).getTitle());
writer.newLine();
for (Par parList : listParText) {
if (parList.getText() != null) {
writer.write(parList.getText());
writer.newLine();
}
}
}
The problem is, that I can't recreate the structure of the document on the stage custom objects -> TeX. Although the structure is preserved on stage XML - custom objects. In Objects model I have, for example:
Section1(title): Par(text), Par(text), Par(text)
Section2(title): Subsection1(title): Par(text), Par(text), Par(text)
Subsection2(title): Par(text), Par(text)
Section3(title): Par(text)
Is there a way to save this order and get value in the same order to write them to file? Get values with getters and setters is NOT a problem to me, problem to retrieve them with proper order.
Update
To clarify the problem, lets suppose every Section contains paragraphs (Par), subsection (SubSec), Tables, Figures in certain order. But obviously Java not allow to make a list like: List<SubSec, Par, Table, Fig>. I can put information there in certain order, but not retrieve. Or can I?

Would it work to make a parent class, say DocumentComponent, of which SubSec, Par, Table, and Fig were all subclasses, and then say that a document is an ordered list of DocumentComponents?

Related

GSON - Serialize ArrayList into a JSON array containing JSON objects without duplicates

I'm currently making a novel reader/editor in java using JSON. I've made the reader part with no problem, but the JSON serialization in the editor is giving me problems.
The idea is to add or set an object to an ArrayList like this:
ArrayList<Chapters> allChapters = new ArrayList<>();
private void TAContentKeyTyped(java.awt.event.KeyEvent evt) {
Chapters newChapter = new Chapters(LSChapters.getSelectedValue(), TAContent.getText());
if (allChapters.contains(newChapter)) {
allChapters.set(0, newChapter);
}
else {
allChapters.add(newChapter);
}
String json = gson.toJson(allChapters);
Iterator allChaptersIterator = allChapters.iterator();
while (allChaptersIterator.hasNext()) {
System.out.println(allChaptersIterator.next().toString());
}
System.out.println(json);
}
which outputs this when I press backspace 3 times:
Chapter: Test Content:
Chapter: Test Content:
Chapter: Test Content:
[{"chapter":"Test","content":""},{"chapter":"Test","content":""},{"chapter":"Test","content":""}]
As you can see, instead of putting all inputs with the same chapter name into a single element, the code uses the .add() method instead of the .set() method every time despite putting a .contains() method on the if. Admittedly I didn't expect this approach to work, but I have no idea how to approach this at all.
The desired output should look like this:
Chapter: Test Content: This is content 1
Chapter: Test 2 Content: This is content 2
[{"chapter":"Test","content":"This is content 1"},{"chapter":"Test 2","content":"This is content 2"}]
Where every chapter with the same name is stored in a single element no matter how many keys were pressed.
Thank you in advance.
The Chapters class look like this:
public class Chapters {
private String chapter;
private String content;
public Chapters(String chapter_name, String chapter_content) {
chapter = chapter_name;
content = chapter_content;
}
#Override
public String toString() {
return "Chapter: " + chapter + " Content: " + content;
}
}
Notes:
Please ignore that the .set() method uses index 0, that's just for testing. The real function would use the chapter name's index.
Maybe you should use Set instead of a List? Change your
ArrayList<Chapters> allChapters = new ArrayList<>();
to - for example :
Set<Chapters> chapters = new HashSet<>();
To Set function correctly you should also implement equals(..) and hashCode() in your Chapters, for example, if you can rely only chapter
#Override
public int hashCode() {
return chapter.hashCode();
}
#Override
public boolean equals(Object obj) {
if (obj != null) {
if (obj instanceof Chapters) {
return chapter.contentEquals(((Chapters) obj).getChapter());
}
}
return false;
}
NOTE: above though working are just examples that use only chapter string as 'id' and not fully tested. See more What issues should be considered when overriding equals and hashCode in Java?.
There is no more need to check duplicates explicitly. You can just add chapters to your set and above changes will ensure no duplicates.
Turns out the main problem is the keyboard event. No matter which listener I use (KeyPressed, KeyReleased, KeyTyped) some kind of indexing error always pops up. I finally relented and gave the function its own button. It works perfectly now. This is the new code:
try {
String contentString = TAContent.getText();
int contentStringLen = contentString.length();
int selectedIndex = LSChapters.getSelectedIndex();
int ArrayIndexLength = sessionContent.size();
if (contentStringLen > 1) {
if (ArrayIndexLength < selectedIndex) {
for (int i = 0; i < selectedIndex; i++) {
sessionContent.add(0, "");
}
}
if (selectedIndex >= ArrayIndexLength) {
sessionContent.add(selectedIndex, contentString);
}
else {
sessionContent.set(selectedIndex, contentString);
}
}
else {
JOptionPane.showMessageDialog(null, "Please write chapter content first!");
}
}
catch (Exception e) {
System.err.println(e);
}

(Data Structure) Java LinkedList objects to Tree

I have a class A like this:
class A {
Long id;
String name;
Long parentId; // refers to another A object's id
}
Now I get the list of A objects, and I want to put them all to a data-structure like "folder tree" in PC, and then view that tree on GUI using JSP but I do not know how to implement this. So could you please help on these 2 problems:
1. How to build a "folder tree" from a given list of objects? Is there any available API support this?
2. How can we browse that whole data tree and view it on JSP as folder tree without using recursion? (I mean what is the best way to display them)
Thank you so much.
Based on your comments, I assume that you can change your A class to look like this:
class A {
Long id;
String name;
Long parentId; // refers to another A object's id
List<A> childrenNodes = new ArrayList();
}
Now, assuming you have a List<A> lstData filled with all the data and you want to convert it into a Tree, you can use the following code/algorithm:
public List<A> convertIntoTree(List<A> lstData) {
for(A parentA : lstData) {
//setting the children nodes for parentA
for(A childA : lstData) {
if (childA.getParentId() == parentA.getId()) {
parentA.getChildrenNodes().add(childA);
}
}
}
//the main tree
List<A> lstParents = new ArrayList<A>();
//filling the tree
for(A parentA : lstData) {
//change this for your check if parent function or another rule
if (parentA.getParentId() == 0) {
lstParents.add(parentA);
}
}
return lstParents;
}

How to implement reference data Java/DB

I've got a table with some factors that I need to incorporate into a Java program. At first I was thinking of hardcoding the number but it seems like a pain trying to create a data structure that will fit the factors. So I wanted to ask around and see if it would be better to implement this as reference data in a database, a flat file or in java. The number would change every six months and would be used for mathematical computations.
Thoughts?
For slow-changing data like this, I would use an external config file. Based on the structure of your data, it seems that a CSV would work well, and would be easy for a business user to edit using Excel.
If it will change more often, you need to generate the data programmatically, or you want to provide a UI for editing the data, you could move it to a database.
You would have to create a data structure to contain the data regardless of how you store them. But the data structure for this kind of data does not have to be complex. It is just a list of values with attributes. You don't have to store them in a complex table-like structure.
Loading the data from a flat text file would also be quite easy when representing the data as a single list.
public class DataTable {
private List<Entry> table = new ArrayList<Entry>();
public double getValue(Sex sex, MaritalStatus maritalStatus, AgeInterval ageInterval, Type type) {
for (Entry entry : table) {
if (entry.sex == sex && entry.maritalStatus == maritalStatus && entry.ageInterval == ageInterval && entry.type == type) {
return entry.value;
}
}
throw new IllegalArgumentException("Unknown value");
}
public void load(String filename) {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(filename)));
String line;
while ((line = reader.readLine()) != null) {
StringTokenizer t = new StringTokenizer(line, ":");
table.add(new Entry(
Sex.valueOf(t.nextToken()),
MaritalStatus.valueOf(t.nextToken()),
AgeInterval.valueOf(t.nextToken()),
Type.valueOf(t.nextToken()),
Double.valueOf(t.nextToken())));
}
} catch (IOException e) {
throw new IllegalStateException("Failed to read the data file", e);
}
}
}
enum Sex {M, F}
enum MaritalStatus {SINGLE, MARRIED}
enum AgeInterval {I16_21, I22_35, I35_55, I55}
enum Type {GD, NGD} // Whatever this is ...
class Entry {
Sex sex;
MaritalStatus maritalStatus;
AgeInterval ageInterval;
Type type;
double value;
Entry(Sex sex, MaritalStatus maritalStatus, AgeInterval ageInterval, Type type, double value) {
this.sex = sex;
this.maritalStatus = maritalStatus;
this.ageInterval = ageInterval;
this.type = type;
this.value = value;
}
}
The data file would look like this:
M:SINGLE:I16_21:GD:1.10
F:SINGLE:I16_21:GD:1.20
...
You could represent it as XML, but that might be a little heavy for such numeric data. But the XML would allow you to be fairly descriptive and self documenting. Then later you could easily parse this into Java(or another language of your choice).
Partial XML example:
<dataset>
<gd>
<16to21>
<single>
<male>1.10</male>
<female>1.20</female>
</single>
<married>
<male>0.90</male>
<female>0.80</female>
</married>
</16to21>
...
</gd>
<ngd>
...
</ngd>
One way that you could break up the fields is gender, age, marital_status, GD_VS_NGD, the data inside the table, and some identifier for the time period that you are using this data for unless you do not need to keep records of the data.

Java/Android get array from xml

I have a list of longitude and longitude points in an xml file that is used throughout my application. I find my self repeating this code to get points often and think there must be a better way?
String[] mTempArray = getResources().getStringArray(R.array.stations);
int len = mTempArray.length;
mStationArray = new ArrayList<Station>();
for(int i = 0; i < len; i++){
Station s = new Station();
String[] fields = mTempArray[i].split("[\t ]");
s.setValuesFromArray(fields);
Log.i("ADD STATION", ""+s);
mStationArray.add(s);
}
XML is in the format of:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<array name="stations">
<item>
<name>Station name</name>
<longitude>1111111</longitude>
<latitude>11111</latitude>
<code>1</code>
</item>
And another (possible) problem is that to get just one station I have to get all of them and pull the one I want from the array. Is this going to be considerably slower? Can I make this array consistent throughout the app? (But keeping the separate Intent methodology)
I had the same thought as MilkJug, to use a utility method to create the stations, but I want to offer a slightly different approach: Move as much of the construction logic as possible into the Station class constructor. To keep the example simple, I'm moving the utility method into the Station class as well.
This provides an overall cleaner design, as outside of the Station class itself, your code should never have to deal with a Station object whose construction/initialization steps haven't been fully completed.
(kgiannakakis's suggestion to use a database may be a better way to go if you have a lot of Station objects.)
public class Station {
private static List<Station> sStationArray = null;
/**
* Construct a Station from a specially-encoded String. The String
* must have all the necessary values for the Station, separated by tabs.
*/
public Station(String fieldString) {
String[] fields = fieldString.split("[\t ]");
// For safety, setValuesFromArray() should be declared 'final'.
// Better yet, you could just move its body into this constructor.
setValuesFromArray(fields);
// I'm assuming 'mName' is the name field for the Station
Log.i("Station", this.mName);
}
public static Station getStationArray(Context ctx) {
if (sStationArray == null) {
// (Please don't use the prefix 'm' for non-member variables!)
final String[] tempArray =
ctx.getResources().getStringArray(R.array.stations);
final int len = tempArray.length;
// Passing the length into the ArrayList constructor (if it's
// known, or can be guessed at) can be a very simple yet
// effective optimization. In this case the performance boost
// will almost certainly **not** be meaningful, but it's
// helpful to be aware of it.
sStationArray = new ArrayList<Station>(len);
for (int i = 0; i < len; i++) {
Station s = new Station(tempArray[i]);
sStationArray.add(s);
}
}
return sStationArray;
}
}
Why not create a utility method that takes a context as a parameter and returns the station resources? For example:
public class StatUtil {
private static List<Station> mStationArray = null;
public static Station getStation(Context ctx) {
if (mStationArray == null) {
String[] mTempArray = getResources().getStringArray(R.array.stations);
int len = mTempArray.length;
mStationArray = new ArrayList<Station>();
for(int i = 0; i < len; i++){
Station s = new Station();
String[] fields = mTempArray[i].split("[\t ]");
s.setValuesFromArray(fields);
Log.i("ADD STATION", ""+s);
mStationArray.add(s);
}
}
return mStationArray;
}
}
and call it from your code with:
stationArray = StatUtil.getStation(this);
Repeatedly fetching the stations will be slower than caching them, but not significantly slower unless you are fetching them in a loop. Doing as above will prevent multiple copies from being fetched.
I could propose two solutions:
You could create a Singleton class that initializes once, reads the data from the XML and stores the stations in a List or a Map. Use a Map if you want to quickly find a station based on its name. The Singleton class will provide methods for retrieving all stations or just one of them.
Create a database table and store the information there. You may need more code, but the advantage will be that you will be able to run more advanced queries.

What is a good java data structure for storing nested items (like cities in states)?

I'm just getting started in Java and am looking for advice on a good way to store nested sets of data. For example, I'm interested in storing city population data that can be accessed by looking up the city in a given state. (Note: eventually, other data will be stored with each city as well, this is just the first attempt at getting started.)
The current approach I'm using is to have a StateList Object which contains a HashMap that stores State Objects via a string key (i.e. HashMap<String, State>). Each State Object contains its own HashMap of City Objects keyed off the city name (i.e. HashMap<String, City>).
A cut down version of what I've come up with looks like this:
// TestPopulation.java
public class TestPopulation {
public static void main(String [] args) {
// build the stateList Object
StateList sl = new StateList();
// get a test state
State stateAl = sl.getState("AL");
// make sure it's there.
if(stateAl != null) {
// add a city
stateAl.addCity("Abbeville");
// now grab the city
City cityAbbevilleAl = stateAl.getCity("Abbeville");
cityAbbevilleAl.setPopulation(2987);
System.out.print("The city has a pop of: ");
System.out.println(Integer.toString(cityAbbevilleAl.getPopulation()));
}
// otherwise, print an error
else {
System.out.println("That was an invalid state");
}
}
}
// StateList.java
import java.util.*;
public class StateList {
// define hash map to hold the states
private HashMap<String, State> theStates = new HashMap<String, State>();
// setup constructor that loads the states
public StateList() {
String[] stateCodes = {"AL","AK","AZ","AR","CA","CO"}; // etc...
for (String s : stateCodes) {
State newState = new State(s);
theStates.put(s, newState);
}
}
// define method for getting a state
public State getState(String stateCode) {
if(theStates.containsKey(stateCode)) {
return theStates.get(stateCode);
}
else {
return null;
}
}
}
// State.java
import java.util.*;
public class State {
// Setup the state code
String stateCode;
// HashMap for cities
HashMap<String, City> cities = new HashMap<String, City>();
// define the constructor
public State(String newStateCode) {
System.out.println("Creating State: " + newStateCode);
stateCode = newStateCode;
}
// define the method for adding a city
public void addCity(String newCityName) {
City newCityObj = new City(newCityName);
cities.put(newCityName, newCityObj);
}
// define the method for getting a city
public City getCity(String cityName) {
if(cities.containsKey(cityName)) {
return cities.get(cityName);
}
else {
return null;
}
}
}
// City.java
public class City {
// Define the instance vars
String cityName;
int cityPop;
// setup the constructor
public City(String newCityName) {
cityName = newCityName;
System.out.println("Created City: " + newCityName);
}
public void setPopulation(int newPop) {
cityPop = newPop;
}
public int getPopulation() {
return cityPop;
}
}
This is working for me, but I'm wondering if there are gotchas that I haven't run into, or if there are alternate/better ways to do the same thing.
(P.S. I know that I need to add some more error checking in, but right now, I'm focused on trying to figure out a good data structure.)
(NOTE: Edited to change setPop() and getPop() to setPopulation() and getPopulation() respectively to avoid confucsion)
If you really need these kinds of aggregation (StaleList that have States, States that have Cities), then this is the correct way to implement. It may not be the most straightforward, but it is the most object oriented approach. So, for the cost of minimalism, you sure get cohesion, coupling, maintainability and all those fancy software engineering adjectives. For small projects, these characteristics should not be enforced. But for big software projects they make sense and avoid really bad code (but do not guarantee really good code).
You can also use some third-party libraries (like the one from Pangea answer) to help keeping the code simple.
See:
1: http://en.wikipedia.org/wiki/Cohesion_(computer_science)
2: http://en.wikipedia.org/wiki/Coupling_(computer_science)
3: http://en.wikipedia.org/wiki/Maintainability
Checkout the Multimap data structure from guava collections. This is not the complete answer to your solution but will simplify to certain level. But the beauty is that now you can use MapMaker to cache your "population queries" against the city.
Multimap<String, City> stateToCities = ArrayListMultimap.create();
stateToCities.put("GA",new City("Atlanta",100000));
stateToCities.put("GA",new City("Cumming",50000));
I would consider using one class to manage a list States containing member variables of City and population in two-dimensional arrays.
Other thoughts:
cityAbbevilleAl is not checked against null.
At first, I misread getPop as a pop method and not population.
Spell out "population". Key strokes are cheap. You've already confused one responser here; it's likely that others won't get it at first, either.
Can population be negative? If not, I'd check that in your contract for setPopulation().

Categories