What approach shall I take if I would need to parse an incoming data with a dynamic set of fields. I can request a List of these fields though, so I know the amount of fields and their names at runtime. I don't know how to construct a model which I would use to parse the data and use afterwards. Thanks a lot for any suggestions.
I'd go with the attribute name/ attribute value pair within a javabean, but, in order to keep track, I'd also add some business class (or interface) enumerating the allowed value for attributes.
Let the code speak:
class MyBean {
String name;
Object value;
// Getters and setters
}
Now, if one of those list rappresents a dog, we may have a class like:
class Dog {
private List<MyBean> dataSet;
// Enumerate the possible values of MyBean.name for a valid Dog object
public final static String KIND = "kind";
public final static String AGE = "age";
public final static String BARFES = "heBarf";
// Use a convenience Set for checks
public static Set<String> validAttributes;
// Put valid values in the convenience set once for all
static {
// trivial code to initialize the validAttributes set
}
// We won't add setters, better constructing a new object every time
public Dog(List<MyBean> v) {
dataSet = v; // better copying ? as usual it depends on scenarios.
}
// A convenience static to parse a string into this object.
public static Dog parse(String theStream) {
// cannot write since I don't know how is format, but this method can use the enumerations of the attribute names for checking.
}
// Accessor
public int getAge() {
return dataSet.get(Dog.AGE);
}
}
Well possibilities are infinite. You can have a base class (a List) and use it as a base class for business classes (adding just getters and proper constructor) or use a List as a private data member (remember to keep it hidden - don't give a direct access to its reference).
You can probably go with some enum too. The important thing, in using this kind of meta-datas (because in the end these are metadatas) is keeping track of valid names (there's no compile checks, so you need to have some sort of quick and dirt way to monitor things).
PS: Don't mind code, is actually just a proof of concept (probably won't even compile).
Though your question is is not clear, I will try to answer. If you know the field names then you will have to do as it is done on command line, supply parameter and retrieve their value.
If you know the delimiter, then parsing is easy. For complex data structure you can construct the syntax with regular expression to parse.
You can use reflection.
Another easy way:
1) parse the dynamic List as a JSON string in a for loop, OR make a map instead of list with the key as field name and value as field value.
2) convert the JSON string or map with any JSON lib.
Related
I want to create a dynamic sql java application. Normaly i create a java pojo with hard coded columns. For Example:
public class DbEntry{
private int id;
private String name;
public setter and getter
}
Now, the problem is, that the user can change the Database columns as he need. For example, he can add new columns if he need and so on. But if he change the columns the hard coded pojo cant representate the whole db entry. I have read over dynamic byte code creation, but i dont really want to use this, if there is an other/better solution.
Consider this class:
public class DbEntry{
List<Integer> integerList;
List<String> strList;
public Integer getInt(int index){
return integerList.get(index);
}
public String getStr(int index){
return strList.get(index);
}
//todo: add some constructors/factory methods
}
For fixed columns, you can write some global constants like staic int I_ID=0 and static int I_NAME=0. So you can get the id and name of an DbEntry by calling dbEntry.getInt(I_ID) and dbEntry.getStr(I_NAME)
For changeable columns you can use a List<String>, add new column names to the list and then you can call dbEntry.getStr(collst.indexOf("name"))
Or you can write a class using strings as keys, so you can call dbEntry.getStr("name"), e.g.:
public class DbEntry{
Map<String,Integer> integerMap;
Map<String,String> strMap;
public Integer getInt(String key){
return integerMap.get(key);
}
public String getStr(String key){
return strMap.get(key);
}
//todo: add some constructors/factory methods
}
This class looks more straightforward but it wastes some memory. Because every dbEntry in the same table has the same set of column names. A single list is enough for storing the column names of a table. HashMap uses more memory than ArrayList. Despite this disadvantage, what data structures to use still depends on your requirements.
Or you may want to make it an interface with getInt, getStr, getDate, getBlob, so you can have the flexibility by implementing the interface using different data structures.
I have seen this done, and it is a lot of work. What you end up doing is having a dynamic model, typically modelling classes and attributes. You expose the Classes and Attributes (and their definition) to a sysadmin role.
The rest of the application sends and retrieves instance data using this dynamic model. As a start, you won't have static Java classes representing them. In your above example, the DbEntry doesn't exist. You'll end up with a generic Model Object that allows you to return DbEntry objects in a common model. Something like
class DynamicObject {
ClassDefinition getClass(); // a ClassDefinition that contains details about DbEntry
Collection<AttributeDetails> getAttributes();
AttributeValue getValue(AttributeDetails details);
void setValue(AttributeDetails details, AttributeValue value);
}
This above is all bespoke code written/defined by you. I am unaware of any third party framework that provides this to you. That said, I haven't looked very hard.
The bottom line is, for what you want to do, the Classes and Attributes end up being modelled by the application and the rest of the application works off that model. Only by doing that, will you prevent the need for making static Java changes when the model changes.
It is not trivial, and carries with it a fair amount of maintenance. I have seen this done, and over time it did become a fairly arduous task to maintain.
Suppose I have, for example, an array of objects generated by parsing a document. These objects look like this:
Object{
id
text
anotherProperties
}
The first two attributes (id and text) are set during parsing, but now I want to add another Properties(additional attributes), which can't be set during parsing, because it is too complicated to determine them, but depends on text.
How can I achieve this in an elegant way?
In Java?
Thanks for responses
Perhaps use a HashMap with key of Integer (your id) and a value of DocProperites which consists of text and anotherProperites.
Then when you are ready to set anotherProperties you can retrieve the object from the HashMap and then set it.
For example
Map<Integer, DocProperties> map = new HashMap();
and DocProperties is
public class DocProperties {
private String text;
private String anotherProperties;
//plus the usual setters, getters and ctor
}
then when you want to set the anotherProperties you can call
map.get(key).setAnotherProperties(....);
If you wanted something more dynamic then you could use another HashMap instead of DocProperties. The HashMap could then have keys added and removed as you parse. I wouldnt advise this though as the code could become very messy and bug ridden.
I'm writing a program with a bunch of classes that will be serialized to save in a database and to be sent through a network.
To make things easier for accessing the class properties via command line interface, I'm considering storing the properties in a Map class, instead of giving each property it's own variable.
Basically, instead of using something like this:
String id = account.getUserId();
I would do this
String id = account.properties.get("userId");
Is this an advisable way to do things?
Yes, it's a pretty sensible model. It's sometimes called the "prototype object model" and is very similar to how you would work in JavaScript where every object is effectively a Map. This in turn has led to the very popular JSON serialisation format.
Nice features:
You don't have to worry about messy inheritance heirarchies - you can just alter the properties at will.
You can create a new object just by copying from another object (the prototype)
Code to manipulate the data can do so in a uniform way, without having to explicitly name all the variables.
It's more "dynamic" compared to a static class definition - it's easy to extend and modify your objects
Potential risks / downsides:
You need to keep track of your property names if you use Strings - the compiler won't do it for you! This issue can be alleviated by using Enums as keys, but then you lose some flexibility...
You don't get the benefits of static type checking, so you may find that you need to write more JUnit tests as a result to ensure things are working properly
There is a slight performance overhead (though probably not enough to worry about, as map lookups are very fast)
I actually wrote an entire game in the 90s using a variant og this object model (Tyrant) and it worked very well.
Rather than having a Map object exposed however, you may want to consider encapsulating this functionality so that you can use an accessor method on the object itself, e.g.
String id = account.getProperty("userId");
How I prefer to do this is often like this:
enum StringPropertyType {
USERID, FIRSTNAME, LASTNAME
}
interface StringAttributes {
String get(StringPropertyType s);
void put(StringPropertyType s, String value);
}
class MapBasedStringAttributes implements StringAttributes {
Map<StringPropertyType, String> map = new HashMap<~>();
String get(StringPropertyType s) { return map.get(s); }
void put(StringPropertyType s, String value) { map.put(s,value); }
}
this gives you compile-time safety, refactoring, etc.
you could also use the stringPropertyType.name() to get the string representation of the enum value and use
Map<String,String>
instead..
I have a class, lets call it 'Words', that reads a file and creates a list of strings.
I then have a class, 'Items', that creates a list of 'description' objects, each description object needs access to the list from 'Words'.
Since the 'Word' list reads a file, I obviously don't want to create that list for each 'description' object. So what would be the best way of accessing that list?
Should I just create a function getList() from 'Words' and pass it to 'Items' constructor, then pass it again to each 'description'? or is there a better way? If I do that, then I would also want to make sure it is only a reference to the list and not a copy since the 'Words' list can get huge.
I am relatively new to java and any help would be appreciated.
I would try to resist the temptation to pass that List of words around. I don't see any encapsulation there.
I might give the class that initializes and manages the word list a method that would take an Item and an interface that would show how to populate or filter that word list for a given Item.
I'm guessing that the number of words associated with an item is a small subset of the larger whole, and the number of items is manageable.
I'd just want to see that you didn't turn objects into dumb structs or data transfer objects that revealed everything there was to know about their internal state. If you can, encapsulate behavior inside an object and hide details and complexity. Clients of that class will thank you.
UPDATE: Based on your comment below, I'd wonder if a relational database is what you really need. An Item needs a List of Descriptions; it's a simple JOIN in a relational database and mapping to objects.
Parsing and populating the tables is a one-time thing. Your Java application can just query for Item instances that have given Descriptions. You can ask it to tell you all the Items that have Description "foo", for example. That could be laborious and inefficient using an in-memory Java object. Let the relational optimizer speed it up for you. You don't have to have all the objects in memory at the same time that way, either. Just query for what you need.
You need to create a class that pupulate the List of String object (singleton), call that singleTon method in constructor of description class to assign reference of list to the description object.
public class Words
{
private static ArrayList<String> words;
public static ArrayList<String> getWords()
{
if(words==null)
{
words=new ArrayList<String>();
//read strings from the file and add them into list
}
return words;
}
}
In description class,
public class Description
{
private String desc;
private ArrayList<String> words;
public Description(String desc)
{
this.desc=desc;
this.words=Words.getList();
}
}
You have two choices:
You can retrieve the list from Words using getList() as you said. You then pass the list into the new description object via its constructor.
You can declare the List in Words as public static. This will allow you to reference the List by class reference; Words.list;
The first solution is probably your best option, as declaring static variables is usually undesirable.
I would like to do as below:
public class Words{
private static List words;
private Words();
public static List getInstance(){
if(words == null){
words = getFile();
}
return words;
}
private List getFile(){
//get file
}
}
public class Items{
public List items = Words.getInstance();
}
I'm sorry I haven't tested this code, hopes it will help you to think out a better way if it's wrong.
I'm working on a java program, and I have several vectors defined and filled (from a file) inside a method. I need to return the contents of all the vectors from the method. I have heard you can put them all in one object to return them. Is that possible, and if so, how? If not, do you have any possible solutions for me? Thanks in advance for your help!
Here is a code snippet:
Object getInventory()
{
Vector<String> itemID=new Vector<String>();
Vector<String> itemName=new Vector<String>();
Vector<Integer> pOrdered=new Vector<Integer>();
Vector<Integer> pInStore=new Vector<Integer>();
Vector<Integer> pSold=new Vector<Integer>();
Vector<Double> manufPrice=new Vector<Double>();
Vector<Double> sellingPrice=new Vector<Double>();
Object inventoryItem=new Object(); //object to store vectors in
try
{
Scanner infile= new Scanner(new FileReader("Ch10Ex16Data.txt"));
int i=0;
while (infile.hasNext())
{
itemID.addElement(infile.next());
itemName.addElement(infile.next()+infile.nextLine());
pOrdered.addElement(infile.nextInt());
pInStore.addElement(pOrdered.elementAt(i));
pSold.addElement(0);
manufPrice.addElement(infile.nextDouble());
sellingPrice.addElement(infile.nextDouble());
i++;
}
infile.close();
System.out.println(itemID);
System.out.println(itemName);
System.out.println(pOrdered);
System.out.println(pInStore);
System.out.println(pSold);
System.out.println(manufPrice);
System.out.println(sellingPrice);
}
catch (Exception f)
{
System.out.print(f);
}
return inventoryItem;
}
Personnally, I'd scrap that approach completely. It seems like you need a Product class:
public class Product {
private String itemName;
private int itemID;
// etc etc
public Product(String itemName, int itemID) {
this.itemName = itemName;
this.itemID = itemID;
// etc etc
}
public String getItemName() {
return itemName;
}
public int getItemID() {
return itemID;
}
// etc etc
}
Then something like this :
public class Invertory {
private List<Product> products = new ArrayList<Product>
// etc etc
public Inventory(String fileName) throws IOException {
// Load file,
// Read each product,
products.add(new Product(...product arguments); //add to array
}
public Product[] getProducts() {
return products.toArray(new Product[]{});
}
}
First of all, use ArrayList instead of Vector. Then use a Map as your return object, with each value of the entry is one of your Lists.
Second of all, a much better approach is to create an object that actually holds each of your fields and return a java.util.List of these objects.
public class Item
{
String id;
String name
Integer pOrdered;
Integer inStore;
:
:
You're doing a few things wrong.
Firstly, don't use Vector. Like, ever. If ordering is important to you, you want List on the API (and possibly ArrayList or LinkedList as an implementation).
Secondly, you're trying to have a large number of arrays have values that happen to line up. That's going to be nearly impossible to use. Just create a class that represents one record, and return the List of those.
Thirdly: do not catch that exception. You don't know what to do with it, and you're just going to confuse yourself. Only catch an exception if you have a really good idea what to do in the error case (printing out an error message without a stack is just about never the right thing).
The signature of your method is the most important part. If you get that right, the implementation doesn't matter nearly as much. Aim for something that looks like this:
List<Item> getInventory(File input) throws IOException {
}
You really should reconsider your design here. You have multiple vectors, each with properties of the same type of thing — an item in your inventory. You should probably turn this into a single class, perhaps InventoryItem, with members for the name, price, etc. Then, when reading in each item, you construct an InventoryItem with the given properties, and return a single Vector<InventoryItem>.
If you're really attached to keeping track of all those individual Vectors, you could just return a Vector[] with all the vectors you have:
return new Vector[] { itemID, itemName, pOrdered, pInStore, pSold, manufPrice, sellingPrice };
Also, as Robin says, you should use the ArrayList container instead of Vector. The only thing that will change is that you need to change all calls to someVector.AddElement to someList.add.
Sounds like this should be tagged "Homework".
Okay, first of all, are you required to use all these Vectors, or is that your own decision? Though some may point out that using ArrayLists is better, I'd do away with them and create your own Item class.
This way, instead of having a conceptual item's properties distributed across multiple Vectors (the way you're doing now) you have 1 Item instance per item, with fields for all the data relevant to that item. Now, you only need one data structure (Vector or ArrayList) for all your item objects, and you can return that structure from getInventory().
The easiest way to declare the object would be something like
List<Vector<? extends Object>> inventoryItem = new ArrayList<Vector<? extends Object>>
but this has several problems, namely that Java's generics aren't reified, so you have to test and cast the contents of each vector that you get back. A better solution would be to define a container object that has each of the Vectors as fields and add to those.
However, this looks like it is really missing the point. Instead, you should define an InventoryItem who has each of your seven fields. Each time you read an object from the file, instantiate a new InventoryItem and populate its fields. Then, you add this to a single Vector.
Also, it is generally recommended that you do not use the Vector class. Instead, you should use ArrayList. Vector should really only be used if you need its synchronization properties, and even then you should consider wrapping some other list in a Collections.synchronizedList().
Finally, the places where you would want to catch just an Exception can be counted on one hand. You should really be catching an IOException and even that you might want to consider just rethrowing. Also, you should call printStackTrace() on the exception rather than System.out.println().
I find that a good rule of thumb is that it's never really a good idea to pass collections around outside your objects. They are obviously useful inside your object, but outside you lose control and they are not obvious.
Consider the principle of making your code readable instead of documenting it. If you take a collection, how does that tell the caller what to pass in? Even if you use generics, there is no way to assert control over what happens to the collection--someone could be adding to it and deleting from it in another thread after it's passed to you.
There is no reason not to create a business class that contains your collections along with the business logic to manipulate them (yeah, there is always business logic--it's the copy and paste code you'll find around the locations that you access the collection).
I used to find it frustrating that the JDK always seems to take arrays of built-in types rather than collections, but it makes a lot more sense after coming to terms with the idea that passing collections (like passing around any basic type) is just not a very good idea.
While in general I heartily agree with the advice to use List/ArrayList instead of Vector, it is important to know why. Indeed, I have to vehemently disagree with Dustin who says not to use Vector "ever".
A Vector is in essence a synchronized ArrayList. If you truly need synchronization, by all means then, ignore Dustin's admonition, and use Vector.
There is another instance in which Vector is justified. And that is when you need to maintain compatibility with a pre-Java2 code base.