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..
Related
Lets say I have a bunch of logically distinct java enums that cannot be merged together since certain prior operations depend on each independent enum.
enum Enum1 {
ENUM1VAL1,
ENUM1VAL2
}
enum Enum2 {
ENUM2VAL1,
ENUM2VAL2
}
void existingOperationOnEnum1(Enum1 enum1);
void existingOperationOnEnum2(Enum2 enum2);
Now lets say I wish to define a new operation that checks whether a string can be converted to any of these enums
void isValidStringConversionForEnums(final String input) {
ENUM1.valueOf(input); // Throws IllegalArgumentException if conversion not possible
ENUM2.valueOf(input); // Throws IllegalArgumentException if conversion not possible
}
So this is great, but its not extensible. The business logic is such that we can have new enums be created in the future (with its own set of enum specific operations), however isValidStringConversionForEnums needs to be updated every time a new one is added, which a programmer might easily forget.
So my question is how would I modify isValidStringConversionForEnums so that it works with future extensions.
One way I thought was to create an interface EnumBase, get the Enums to extend that and then use reflection to get all Enum impls, but I do not wish to use Reflection in Runtime unless I have to.
Is there an alternate way in which this can be written such that I add a new enum and somehow isValidStringConversionForEnums handles that new enum.
You have 2 independent problems here:
Given a list of enum types, how do you write code that tests that your string is convertible to at least one of them?
How do you obtain that list.
These 2 problems are completely unrelated. So, you solve them separately.
Given a list...
Class<? extends Enum> is probably your best bet.
enum Test1 {
FOO, BAR;
}
enum Test2 {
FOO, BAZ;
}
public static void isValidStringConversionForEnums(String in, Class<? extends Enum>... enumTypes) {
for (var enumType : enumTypes) {
for (var c : enumType.getEnumConstants()) {
if (c.name().equals(in)) return true;
}
}
return false;
}
This isn't particularly efficient - but you get the gist. You can pre-make a HashSet containing every valid value and then it's just a .containsKey() call, using the above code to instead serve as a one-off "init" that makes that HashSet for example. If you actually need the enum constants, make a Map<String, List<? extends Enum<?>> instead. computeIfAbsent is a nice way to create those lists on the fly in a one-liner.
Discovery
The java classloader abstraction system simply doesn't have 'give me a list of all files in the jar' or 'give me a list of all classes'. Some libraries appear to provide those features but they are hacks that do not always work, so you probably don't want to use those.
The standard solution for this problem, used by the JVM itself too, is 'SPI' - with module-info.java it's baked in, if you don't use that (and you probably shouldn't, it's kinda tricky, that), there's ServiceLoader. To make the service files, you can use annotation processors, I think there are a few around that automate it.
Then the process flow is simply, to make a new enum, stick a #ProviderFor(Something.class) on it, where Something.class is some marker interface of your design.
Note that wanting to scan all enums on the entire classpath is just plain bad. There are all sorts of enums that java uses internally, what if one of those so happens to have a value in there equal to one of your strings? That does NOT all of a sudden make that a valid string. No, only enums you explicitly mark as applying to whatever this question is, qualify, this, you need to do something to mark them. Either with an annotation, or explicitly by writing out the full list.
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.
I need to write a function which returns a string which should be unique for each state of the object.
i.e. if any of the instance variables are changed, then this method should return another string which should be unique for the given set of instance variables of object.
Similarly I would later require write another method which represents unique static state of the class.
Please suggest any efficient ways to achieve my requirement.
Thanks,
Harish
If you want to track the changes to a given object's state (in its own boundary), this is achievable with a bit of coding or adopting an already implemented approach. Is that what you are asking? What does make using an incrementing serial number inappropriate in your case?
If you are about to guarantee uniqueness amongst all the existing instances of a given class, this is a bit hard. You might need to distinguish an object individually, then asking each object for their unique string representation.
I'd recommend reading about Object.hashcode(). The ideas recommended for hashcode generation could be used for the purpose you want.
You can use Java reflection to find all the fields in your class and work from there:
public String tos() throws IllegalAccessException {
StringBuilder b = new StringBuilder();
for (Field f : getClass().getDeclaredFields()) {
f.setAccessible(true);
b.append(f.get(this));
}
return b.toString();
}
A fairly naive approach would be to serialize the object to memory and take a secure hash of the content. Quite inefficient but it works with any serializable object.
What are the requirements exactly?
Do nested objects also affect state (or is this applicable)? if a.b.c changes does this affect state of a?
Do two different objects with the same content have to end up with the same string?
Is it possible to create new variables in java dynamically.
class A {
methodA(String variableName) {
}
}
So if new method is called twice, 2 new variables should be newly added to this class?
Is it possible?
No. Have you considered storing a Map<String, Object> in the class instead? The keys in the map would be the "variable names" and the values in the map would be the logical variable names.
If you could give more information about what you're trying to achieve (from a high-level perspective) that would help.
No, this is not possible to do in Java.
The fields in a class is determined at compile time and can't be changed during runtime (except though sophisticated techniques such as class reloading though for instance JRebel). I would however not recommend doing this, unless you're writing some IDE for instance.
A class and its members are defined and then compiled to bytecode, so they cannot be readily modified at run-time. That said, there are a number of libraries out there, such as cglib, which provide runtime modification functionality. This page can tell you more: http://java-source.net/open-source/bytecode-libraries
(This is not to say that runtime modification is the right thing to do!)
In a good design, a class must represent something, semantically speaking. You design it to represent an object in your system.
If you want to add more things to a design in run-time, well, something's not quite right -- unless, of course, the design needs adding information in run-time, and there are tons of data structures just ready for the job!
Check out Maps in Java, for example.
Following is the way that i have implemented and helped me to fix my solution easily without much hurdles.
// Creating the array List
List accountList = new ArrayList();
for(int k=0;k < counter;k++){
accountList.add(k, (String)flowCtx.getValueAt("transitId"+m));
}
Iterating the loop and adding the objects into the arraylist with the index.
//Retrieving the object at run time with the help of the index
String a = accountList.get(i));
Using a HashMap could be a solution. For example, if we have the following class:
class Staff {
private HashMap<String, Object> mylist = new HashMap<String, Object>() ;
void setNewVar(String s, Object o) {
mylist .put(s, o);
}
HashMap<String, Object> getVar() {
return mylist;
}
}
I can use it as:
staff.setNewVar("NumVars",11);
staff.setNewVar("NumBatches",300);
...
and then:
staff.getVar()
wherever you need. I use it to convert some variables (the number can change) to JSON, successfully.
We use code values in our database, and Enums in Java. When querying the database, we need to take a code value and get an Enum instance.
Is it overkill to have a HashMap to avoid iteration? What would you do? Is there an easier way?
public enum SomeEnum
{
TYPE_A(2000), TYPE_B(2001);
private int codeValue;
private static HashMap<Integer, SomeEnum> codeValueMap = new HashMap<Integer, SomeEnum>(2);
static
{
for (SomeEnum type : SomeEnum.values())
{
codeValueMap.put(type.codeValue, type);
}
}
//constructor and getCodeValue left out
public static SomeEnum getInstanceFromCodeValue(int codeValue)
{
return codeValueMap.get(codeValue);
}
}
That's exactly the approach I'd take to solve that particular problem. I see nothing wrong with it from a design point of view, it's intuitive, efficient and (as far as I can see) does exactly what it should.
The only other sensible approach I can think of would be to have the map in a separate class and then call that class to update the map from SomeEnum's constructor. Depending on the use case, this separation could be beneficial - but unless it would have a hard benefit I would take your approach and encapsulate everything within the enum itself.
Thanks, I guess my main concern is memory usage, and if it is worth it.
Unless that enum has thousands of values, memory usage will be trivial. (And if it does have thousands of values, then using iteration to do the lookup would be a major performance killer.)
This is a sensible use of memory, IMO.
Perhaps I am over thinking this.
Perhaps you are.
I think in this case we can't avoid iteration. It's either HashMap doing it, or we wrote our own iteration code.
If performance really does matter maybe you can try a binary tree approach.
If your enum space is dense, that is, not a lot of unused values, you could use the toString() and valueOf() methods. Name your values with a common string prefix, then attach the prefix before using valueOf() and strip it after using toString(). This has the disadvantage that you would have to convert to a numeric value if that's how it's stored in your database.
Alternatively, you could add common methods for conversion and assign your database value to a specific enum value.
Both these techniques have the advantage of leveraging the design of enum classes.
There is a lot of good, mind-bending information about enums (and Java, in general) at http://mindprod.com/jgloss/enum.html.
Though, there's nothing wrong with your way if it does the job you want.
That's fine. Don't worry about tiny performance differences.
One would think that if there are only two instances for an enum, like in your example, a trivial code of iterating would be faster:
public static SomeEnum getInstanceFromCodeValue(int codeValue)
{
for (SomeEnum type : SomeEnum.values()) {
if(type.codeValue == codeValue)
return type;
}
}
But there's a hidden cost, quite expensive one if we do care about performane at such level. It's fixable, but you need to see it first:)
To get the ID:
EnumDay day = EnumDay.WEDNESDAY;
int myID = day.ordinal();
To load the day from the myID:
EnumDay dayCopy = EnumDay.values()[myID];