I learn how to handle properties, on a test project, that are written in a yaml file.
I know that it is very similar to handling JSON files.
I learned that I have to write a class/objects composition model that will mirror the yaml configuration.
I did it, and I have to say that everything works pretty well but suddenly I've met a difficulty.
I mean, what if I will add a new property to yaml, that will not have a mirror object in a composition model?
I want to write a code that will read the property just after I will add it to yaml, and I have no idea how to do that.
Does anybody have some suggestions?
If you're looking for named properties, you're out of luck. You need them in your class. However, you can use some more generic collections instead, and fetch the properties by name, assuming they're something simple like key/value.
For example, if you have YAML like this:
size: 16
crust: "wheat"
toppings:
"cheese": "normal"
"pepperoni": "normal"
"onion": "normal"
"mushroom": "extra"
You could have a fixed set of toppings like this:
public class Pizza
{
private int size;
private String crust;
private Toppings toppings;
}
public class Toppings
{
private String cheese;
private String pepperoni;
private String onion;
private String mushroom;
}
But in reality, we all know everyone wants something different on their pizza. If you were to only have the same pizza for everyone, you'd go out of business. So, you need something a little more flexible for toppings. Sometimes they'll be there, sometimes they won't be. So, you have to use a more flexible data structure:
public class Pizza
{
private int size;
private String crust;
private Map<String, String> toppings;
}
Most serializers (e.g. Jackson) know what to do with collections like Map or List. They'll allow you to add whatever property you want, so long as it fits the form/type of the collection.
Related
I have a program that recruits witness accounts of a crime scene from various subjects.
Every kind of subject has its own Report class. For example:
public class EyeWitnessReport extends AbstractReport {
private String details;
private String relation;
private QuestioningResults questioningResults;
private Integer stressLevel;
private EnumSet<CrimeFacts> crimeFacts;
private Religion religion; //to see if swearing on the Bible is an issue
}
public class ExpertWitnessReport extends AbstractReport {
private Expertise fieldOfExpertise;
private boolean relatedToAccused;
private List<Conflict> conflicts;
}
The main function of my app takes all the reports and merges them together into one CrimeScene class that contains all the details of the crime scene (by priorities, etc)
public CrimeScene mergeReports(List<AbstractReport> sources){
//takes all the reports in sources and returns one CrimeScene with the most relevant fields
}
My question is, the CrimeScene class is basically made up of data from the reports, after certain logic. It has 70 possible fields (the fields of every type of report) although on average only around 10-20 are filled.
Plus it has 2-3 fields of it's own (creationTime, reportingOfficer, etc...)
How should I go about implementing it?
Is it a better implementation to make CrimeScene a regular class (70 hardcoded fields, of which no more than 20 will be filled on average), or a dynamic class, using DynaBean, Map<String, Object> or something of the sort?
It is better to use class with properties or maybe some composite class which would allow you to limit number of properties in a single class due to composition.
With this approach you (and any other developer) will know exactly which properties and of which types does object have.
If you go with map then you will lose type safety because you will have to use Map<String, Object> to accommodate values of properties of different types. Also with map approach the only way to know which properties exist (which keys are added to the map at runtime) is to debug your code.
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 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.
Good day, i will try and explain myself here. i am trying to create like a quiz system where an image is mapped to an answer and other wrong answers are provided. An example is like this:
<Image> <answer A> <answer B> <answer c>
I was thinking of using a hash map for the image and correct answer, and maybe an array or an arrayList for the other wrong answers. But i don't know if hash maps works well this way.
what would be the best solution to go about this or any other ideas?
by the way, i would be inputing the values myself and the Image is stored in a resource so its not being downloaded. Thank you
Why not just define an object with an image member, and the correct/incorrect answers ?
public class ImageAnswer {
private final Image image;
private final String answer;
private final String[] wrongAnswers;
// constructor and methods follow.
}
(note sure about the name - depending on its behaviour you can rename appropriately)
That way you can define everything together (atomically) using a constructor, and embed behaviour particular to that within the object.
Remember - objects should do this for you, not provide fields for you to do things with.
What you want to do is create an object you can place all of that data in and keep it in one place.
So for example:
class Question {
Image image;
String correctAnswer;
String[] wrongAnswers;
}
Then you can just play around with Question objects instead of trying to keep everything synchronized across multiple collections.
How about following:
class Answer{
String description;
Boolean correct; // true if correct and false otherwise
}
and a HashMap:
HashMap<Image,ArrayList<Answer>> quiz;
I would do it:
public class Question
{
private Image image;
private String[] options;
private int rightAnswerIndex;
//the rest of the code; you could create a constructor that sets all the member vars
...
}
That way it would be much simpler to iterate through and display the options for the user. If you put the right answer separate from the other options you would always have it displayed as the first or last option.