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.
Related
I have a requirement as follows:
Read data from CSV file.
Find duplicate rows based on key passed. (Say example, CSV file has 10 columns, we need to find duplicates based on a particular row
key)
A boolean to reject/accept duplicate rows.
Cell Processors to validate each row in the file.
This is for a bulk upload data where I read the file row by row, find if the row has valid data and the row is not duplicate based on key passed and finally return a list of valid rows.
abstract class BulkUploadService {
List<BulkDTO> process(File file) {
// Read a file and the value from below methods overridden by their child classes
}
abstract CellProcessors[] cellProcessors();
abstract boolean isDuplicatesAllowed();
abstract String[] headers();
abstract String rowKey();
}
The method process() needs - File, Row key, CellProcessors, boolean to accept/reject duplicates, and few more to process and return a list of valid rows in the form of DTOs. The child classes will implement BulkUploadService and override all the methods except process() to supply data for the process() method to return a valid list.
The reason I want to abstract out is this BulkUploadService should handle all the business logic and return a valid list for the concrete classes and the concrete classes should focus just on supplying information. Is there a better way to design for this scenario?
I am not a big fan of inheritance and don't understand why you are using it here.
You've clearly defined two responsibilities:
processing data (1);
collecting requisite parts for processing (2).
Now, your subclasses are supposed to take both responsibilities, which is not correct.
I suggest you design separate classes for (1) and (2).
class BulkUploadService {
private BulkUploadDataCollector collector;
List<BulkDTO> process(File file) { ... }
}
interface BulkUploadDataCollector {
CellProcessors[] cellProcessors();
boolean isDuplicatesAllowed();
String[] headers();
String rowKey();
}
If you scrutinise BulkUploadDataCollector, you will notice that it's up to fetch and store data (too many duties again).
I would write a DTO class (let's say BulkUploadData) which will free BulkUploadDataCollector (now, renamed to BulkUploadDataFetcher) from storing data and loosen the coupling between BulkUploadDataFetcher and BulkUploadDataService.
These two wouldn't know about each other and would work exclusively through BulkUploadData instances.
I am working on a project to help get me back into Java coding and it is a text based game (I know, not much, but I have to start somewhere).
Anyway, I have come across a problem. I need to be able to put names of parts (it is a hardware tycoon game) and prices along with them into an array. For example, a desktop computer has parts such as a CPU, and the game would list your CPU choices. I need a way of storing this data, and it's pretty complicated to me because I need to not only store all of the names of CPUs for the player's benefit, but also store the prices alongside the names. On top of that, I have multiple product types such as desktops, laptops, and consoles, which each pretty much have different part names and prices.
I thought of a 3 dimensional array to store the product types such as desktop (in columns), the part names (in rows), and the prices (behind the rows, if that makes sense in a 3 dimensional way. But I do not know how to initialize such an array and how to set the values on initialization.
Also, I thought of creating classes for each product type and putting arrays in each class to define parts and prices (2d arrays), but it is still complex and I would like to know how to sort this data and potentially make a system where certain parts are unlocked as game time progresses. Thank you in advance.
I might take you in a different direction. Why don't you create classes and objects? Then create instances of those objects? Java is an object oriented language. Creating objects would allow you to hold all of the values you need. Quick example,
Public abstract class CPU {
// Declare fields
private float price;
private String name;
// Declare constructors
}
Public class intelCPU extends CPU {
// GetPrice
public int getPrice() {
return price;
}
// Set Name
public void setName(n) {
name = n;
}
}
I agree with #Regis that you should be using a custom object to describe your products, and then storing them in a some kind of data structure.
However, you can solve the problem you described by declaring a multi-dimensional array of the type "Object," which will allow you to put basically anything into it, even primitives (autoboxing and autounboxing was added in Java 5 and will seamlessly translate between primitive types like int and the Java wrapper class for that type, like java.lang.Integer).
Of course such an array would be very weakly typed and there would be nothing stopping you from adding doubles to the product name column, or vice versa. You'd also have to do a lot of casting, which is a code smell.
How about using a Map instead. A Map let's you store information in Key/Value pairs. You can make a Map that has a key type of String (that represents the product type) and a value type of Map (that represents individual products) that has a String key (product name) and a value that stores the price (perhaps a double) or the info (as a String or something). That way you can do something like outerMap.get("laptops").get("laptop1") and that would return the information of laptop1. The first get, gets the Map that contains all of the laptop products (or whatever product type ypu would want). The second returns the information for the specific product in that category.
You can implement this like this.
Map<String, Map<String, String>> productMap = new HashMap<>();
Using this you would place a product type like this:
productMap.put("laptops", new HashMap<String,String>());
And then add a product like this:
productMap.get("laptops").put("laptop1","This is information about laptop 1");
PS: In case you aren't aware, the reason I used = new HashMap instead of = new Map is because Map is an interface not a class. A HashMap is a class that implements the Map interface.
More than multidimensional arrays, you could tag this with Object Oriented Programming (OOP). From your description it looks like you would need a class hierarchy, something like:
abstract class Product
class Desktop extends Product
class Laptop extends Product
class Console extends Product
Put all common fields/methods that can be used by Desktop, Laptop, Console etc into your Product class.
//Just an example
abstract class Product {
String name;
ArrayList<Component> components;
public String getName(){
return name;
}
}
Since each product has several components the product needs to have a list of components as shown above.
abstract class Component{
Double price;
public Double getPrice(){
return price;
}
}
Now you can have components like CPU, Power supply etc, they have some common behavior and fields like price that is put into Component class. Any specialized behavior / fields for each component can be put into the corresponding class like clock frequency shown below:
class CPU extends Component {
Double clockFreq;
}
So if your list of parts is 3 items long it could be written to a text file like so:
name,type,price
intelCPU6600,CPU,200
amdCPU7789,CPU,150
PS1Power,PSU,120
newPart,unknown,500
This list could be 100's of items without any problem. Read it into your program using Scanner & for each line do something like:
String line = scanner.nextLine();
String[] fields = line.split(",");
if("CPU".equals(fields[1]){
CPU cpu = new CPU(fields[0],fields[1],fields[2]);
//Product is an object of the class Product that you should have created earlier
product.components.add(cpu);
} else if("PSU".equals(fields[1]) {
PSU psu = new PSU(fields[0],fields[1],fields[2]);
product.components.add(psu);
} //..so on
if there is a generic product that you don't have a class for that's where the abstract class can be used:
if("unknown".equals(fields[1]){
Component comp = new Component(fields[0],fields[1],fields[2]);
product.components.add(comp);
}
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.
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'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.