Java - Constants and where to hold them - java

Ok so I've been reading up on good practices for using constants and enums but I still am confused as to what should I do.
Basically I need to store strings with paths to assets like
"/assets/sprites/ball.png"
and then i need simple name strings like "ball" and I want them to be related to each other.
Those strings will be used very often and in different files/packages all across my game's code.
I have a TextureAtlas class that given the name ("ball") already provides me with the actual resource (graphics ready to draw etc). But when I need to load the resource i need to give actual path, not just name. I want to have 1 place where I will have all the constants declared and it would be nice if both the "name" constant and "path" constant were related somehow. So that I don't have to put actual path to the file whenever I want something to use that graphic, instead I want to use constant with the name String.
I hope you can understand what I mean.
Well, I think I could use a map, where key would be the name ("ball") and value would be path ("/assets/ball.png") but I still want to be able to just lets say, write something like this
Assets.GetSprite(Assets.BALL);
and get an actual resource, or even better
Assets.GetSprite(BALL);
So there is this problem of constants, that I need to define name and corresponding path for my graphics in 1 place and be able to use it from anywhere in the program if I need it.
It all needs to be in one place so that whenever I add new resource, like new sound or new sprite to the game I won't have to look all over my program to find the place where it should be manually typed, I want to have that 1 file that I will go over and just add new constant or something like that for that 1 file.
Cheers,
Pablo.

It might be a good idea to use properties file.
Java Properties
config.properties
ball = /assets/sprites/ball.png
user = /assets/sprites/user.png
To read these values, at the game startup, do following
FileHandle propertiesFileHandle = Gdx.files
.internal(PROPERTIES_FILE_PATH);
PROPERTIES = new Properties();
try {
PROPERTIES.load(new BufferedInputStream(propertiesFileHandle.read()));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Now you can share this PROPERTIES object wherever you need.
String ballPath = PROPERTIES.getProperty("ball");
Hope this helps.

What is the problem with the Map? Create a static HashMap and store you mapping there. You can directly get your values from there.
OR
if you simply need mappings where you key and values are constants then you can put them in an interface (Variables are by default public static and final).

I would go for something like this:
public enum Assets {
BALL, PLAYER // and so on
}
public class Configuration {
Map<Assets, String> values= new HashMap<Assets, String>();
public String getPathFor(Assets asset){
if(!values.containsKey(asset)) throw new IllegalArgumentException();
return values.get(asset);
}
/* Contains further logic to persist configuration */
}
So you have well defined Assets and a Configuration object, where you store further Information.

You can create more complicated enums with parameters. Take a look at the Planet enum in this example http://docs.oracle.com/javase/tutorial/java/javaOO/enum.html or here is an example specific to your project. Remember that are required to create the constructor and the constructor must be private.
public class Asset {
public enum AssetType {
BALL("/assets/sprites/ball.png"),
USER("/assets/sprites/user.png");
private final String path;
AssetsType(String path) {
this.path = path;
}
public String getPath() {
return this.path;
}
}
private AssetType assetType;
public Asset(AssetType assetType) {
this.assetType = assetType;
}
// ...
}

Related

How to automatically add new variables to files in Java?

So I have this class.
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
public int health;
public String name;
}
I load the Player when they "connect", and I save the Player when they "Disconnect".
I save and load using the Object Input/Output stream.
Later on, I want to add a gold variable to the Player.
So the code will be:
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
public int health;
public String name;
public int gold;
}
I still want the file to contain the health and name, but I want to update it with the gold variable; how would I go about doing that?
I know I can check if the gold is null, and if so append it to the next save. But is there a way where I can add as many variables as I will, and the code will automatically save the new variables in the class?
Is there a way for the code to automatically add new variables to the file?
Load Player:
try {
final FileInputStream fileInputStream = new FileInputStream(file);
final ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
try {
user = (User) objectInputStream.readObject();
} catch (ClassNotFoundException exception) {
exception.printStackTrace();
return false;
}
objectInputStream.close();
fileInputStream.close();
} catch (IOException exception) {
exception.printStackTrace();
return false;
}
Save Player:
try {
final FileOutputStream fileOutputStream = new FileOutputStream(file);
final ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
objectOutputStream.writeObject(user);
objectOutputStream .close();
fileOutputStream.close();
} catch (IOException exception) {
exception.printStackTrace();
return false;
}
Java is strictly typed. Adding a field at runtime, though possible would take some of the dark arts (modify classes at runtime).
It seems to me you are better off basing your player on HashMap as internal data structure. It can be serialized and deserialized the way you need and allows you to add more values at runtime.
Java's built-in object serialization is not very flexible when you need to support different versions. You should change the serialVersionUID of your updated class. But then you won't be able to deserialize older versions. Some possible solutions are:
Define your own readObject and writeObject methods (see Javadoc on ObjectInputStream for details). Then use these to serialize/deserialize a Map of variable names to variable values, using this map as a transfer object to/from your actual class.
Use a different serialization mechanism, such as JSON. Libraries like Jackson are quite flexible in their ability to specify default values for missing fields.
If the contents of your Player class changes only occasionally, you could try the following:
Create a new class containing the new fields, calling it e.g. PlayerV2.
Create a separate program that goes through each of your saved player files. For each file you load the old player object; convert it to a new player object, then save the new player object.
Start using the new player class in your game.
If the player objects are expected to vary a lot over time, and maybe different players will have different contents in their objects, then go with a Map as suggested by the OP.
In this case, you should probably have a version entry in the map. This way you can detect when a player has been saved by an older version of your game, and provide some form of automatic upgrade of the contents of the map, if needed.
Alternatively, you should consider saving to a text-based format like JSON. This way, your savefiles are not as directly tied to a Java class as is the case when using Java serialization. Also, it will be easier to debug, and easier to make tools that handle the savefiles directly.

Create JSON File Serializing the class in Java

I have the following class:
public class PDFValues {
private String value;
private int xPos;
private int yPos;
public PDFValues(){
}
public PDFValues(String value, int x, int y){
this.setValue(value);
this.setX(x);
this.setY(y);
}
public void setValue(String value){
this.value = value;
}
public void setX(int x){
this.xPos = x;
}
public void setY(int y){
this.yPos = y;
}
public String getValue(){
return this.value;
}
public int getX(){
return this.xPos;
}
public int getY(){
return this.yPos;
}
}
And then I want to do this:
public class PDFtoJSONTest {
public static void main(String[] args) {
List<PDFValues> listaElementos = new ArrayList<PDFValues>();
listaElementos.add(new PDFValues("Anubis Lockward Botello",
new Integer(100), new Integer(633)));
....more code
}
}
What I want to do, is save all the PDFValues in the ArrayList, as a JSON file, but I don't know how to make it automatic, I thought of Serializing the object or something, but I can't find a solution to this and I'm not sure how I could make the PDFValues object serializable.
I want to do this to save those values in a JSON file and then use them as properties to generate a PDF file, I'm using PDFBox for the generation of the PDFs files and SimpleJSON for the .json ones.
I'm working on a project where I'd have to generate thousands of pdf files out of some processed data. I've already managed to parse the data which consists of about 500+ MBs of text and holds around five thousand account statements which need to be generated as PDFs.
The thing is, that seeings as the Text data is generated in PDFs, one needs to indicate the position of the starting character in a string to PDFValues, to generate a PDFTextInfo object and then add it to the PDF, the file would need to contain images and text and other stuff.
Note: If there's a better way to accomplish what I'm trying to do, I'm open to suggestions, but I'd also like an answer to what I'm trying to do, and know if it would work or not, and why for both cases.
I'd like to make my code as fast as possible, right now I'm able to process the whole TXT file from RAW to mostly clean data in under 2 minutes and I know it might be optimized but right now that's not the point :D
I'd like to generate the PDFs files as fast as possible, but I've been working with that project in Java for like 1 1/2 months now, and I've only learned about JSON and PDF file generation in the past week...it's been three days of working on the JSON file and I'm a bit lost.
Here's an example of the file output for the JSON file that I'm trying to accomplish, this one I generated it manually and I managed to read and process the file, now I'm trying to generate it automatically:
{
"Header": {
"FullName":
{
"Name":"Anubis Lockward Botello",
"Horizontal":180,
"Vertical":633
},
..... more elements .....
}
}
As you can see, I'm trying to divide the elements on the pdf files as if they were panels, like HEADER, BALANCES, TRANSACTIONS and stuff, and build the PDF file as if they were pieces of a puzzle, but right now I'm trying to "build" the name element on the header.
I would guess there is a better way to do build PDF files than writing and then re-reading a file, but I can provide one answer for your JSON question.
Use the Apache commons-lang3 library and look into ToStringBuilder. You can then define a toString() method on your object and use the built-in ToStringStyle.JSON_STYLE format. You'd then have to wrap your list of PDFValues in some other object that can store a PDFValue for Header, FullName, etc..
#Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE)
.append("Name", value)
.append("Horizontal", xPos)
.append("Vertical", yPos)
.toString();
}
I should note that you could pull in Jackson or similar libraries, annotate your objects with the required JsonProperty annotations and use the library to serialize your object to JSON as you would for REST or similar. But, for a simple use case like yours, the ToStringBuilder is simple and effective.
OK, I managed to get this far thanks to JudgingNotJudging, what I did was taking his answer and applying a Decorator Pattern to the object, so that I have a PDFValue, that's inside a PDFElement, that's part of a PDFContainer, so it goes like this:
Header: (this is our PDFContainer)
FullName: (so, Header HAS-A FullName element)
PDFValue: (and FullName HAS-A a PDFValue, that has the Name or value to be shown, and the X and Y coordinates inside the PDF)
Here's the code:
The PDFValue class is still the same, and I added the overridden toString() method according to JudgingNotJudging's answer.
public class PDFValuesDecorator extends PDFValues{
}
In PDFValuesDecorator we don't do anything, we're just going to extend PDFValues so that we have the correct type of the class we want to add behavior to, and still get a common type for all the different classes we might create this way.
public class PDFElement extends PDFValuesDecorator {
private PDFValues pdfValue;
private String elementID;
public PDFElement(PDFValues pdfValue, String elementID){
this.pdfValue = pdfValue;
this.elementID = elementID;
}
#Override
public String toString() {
return new ToStringBuilder(this, ToStringStyle.JSON_STYLE)
.append(elementID, pdfValue.toString())
.toString();
}
}
In the constructor we save the instance of the object we're trying to "wrap" so that we can "add" something to it. In this case, we're adding an ID for the element and we're modifying the toString() method of the element to also include the toString() method of the PDFValue, so that they both show both of their values in the appropriate order.
Finally, here's my main method:
public class PDFtoJSONTest {
public static void main(String[] args) {
List<PDFValues> listaElementos = new ArrayList<PDFValues>();
PDFValues name =
new PDFValues(
"Anubis Lockward Botello",
new Integer(100),
new Integer(633)
);
PDFElement fullName = new PDFElement(name, "FullName");
PDFElement header = new PDFElement(fullName, "Header");
listaElementos.add(header);
for(PDFValues value : listaElementos){
System.out.println("Valor: " + value.toJSONString());
}
}
}
As you can see, the first thing I do is create an ArrayList of PDFValues, then I create a single object for the name value, then that name is wrapped inside the FullName element, and then that's stored inside a Header element. As you can see, I can pass around the List object and do with it whatever I want.
And also, I could create other PDFElements like images and stuff, and I can save all of them inside the ArrayList and pass them around and then when I want to save them, I just have to call the toString method once and I would get the correct output, btw, here's the resulting value from the JSON string:
Valor: {"Header":"{"FullName":"{"Name":"Anubis Lockward Botello","Horizontal":100,"Vertical":633}"}"}

Best practice for maintaining constants in Java

I have an old doubt about constants in Java Projects maintenance. From my perspective, when we try putting the constants inside an Abstract class like that:
public final class MyConstants {
public static final String CONSTANT1 = "const1";
public static final String CONSTANT2 = "const2";
public static final String CONSTANT3 = "const3";
public static final String CONSTANT4 = "const4";
}
after that using those constants inside classes in the project:
public void myMethod(final Map params) {
final String myparam = (String) params.get(MyConstants.CONSTANT1);
//DO SOMETHING WITH PARAMS
}
It leads to boiler plate code, verbose use of constants and no real advances. In other hand if we put those constants inside the class for somehow people don't like it. They say "what about we have the same constant declare somewhere?" the problem is maintainance issues, if we change those constants in that class the change can be visible on several parts without any big problem.
Those constants are mainly used for mapping webservices for java perspective without having to generating POJOs like JAXB based on WSDL, the webservices operations are mapped directly for key value maps in Java.
I want to know what do you think about this approach and if we have any other choice.
Thank you.
If I understand your concern, don't hardcode those constants as values except perhaps as defaults and store them with Properties and/or ResourceBundle(s). You might also read the Java Tutorial on Properties. Something like,
Properties props = new Properties();
FileInputStream in = new FileInputStream("my.proprties");
props.load(in);
String v = props.get("CONSTANT_ONE", "const1"); // <-- the "1" is a default.
Then if you need to change the property later you only have to modify the properties file.

java best data structure for two to many relations

So I have three important factors, filenames which there are many, there will also be duplicates, violation types which there are 6 of, and the data relating to them.
I was thinking of using a Map for this but it only accepts two types, so I want to sort the data by the filename and for every entry under that filename, i want to retrieve the violation type, from what i want it to retrieve all the matches from the data, so say it's a map I could of said map.get(filename, violation) and it will retrieve all the results that match that.
Is there a data structure that can allow me to do this? or am I being lazy and should just sort the data myself when it comes to outputting it.
One other way to approach this would be to use a custom Class for holding the needed data. Essentially 'building' your own node that you can iterate over.
For example! you could create the following class object: (Node.java)
import java.util.*;
public class Node
{
private String violationType;
private String dataInside;
public Node()
{
this("", "");
}
public Node(String violationType)
{
this(violationType, "");
}
public Node(String violationType, String dataInside)
{
this.violationType = violationType;
this.dataInside = dataInside;
}
public void setViolationType(String violationType)
{
this.violationType = violationType;
}
public void setDataInside(String dataInside)
{
this.dataInside = dataInside;
}
public String getViolationType()
{
return violationType;
}
public String getDataInside()
{
return dataInside;
}
}
ok, great, so we have this 'node' thing with some setters, some getters, and some constructors for ease of use. Cool. Now lets see how to use it:
import java.util.*;
public class main{
public static void main(String[] args){
Map<String, Node> customMap = new HashMap<String, Node>();
customMap.put("MyFilename", new Node("Violation 1", "Some Data"));
System.out.println("This is a test of the custom Node: " + customMap.get("MyFilename").getViolationType());
}
}
Now we have a map that relates all of the data you need it to. Now, you'll get a lot of people saying 'Don't reinvent the wheel" when it comes to things like this, because built in libraries are far more optimized. That is true! If you can find a data structure that is built into java that suits your needs, USE IT. That's always a good policy to follow. That being said, if you have a pretty custom situation, sometimes it calls for a custom approach. Don't be afraid to make your own objects like this, it's easy to do in Java, and it could save you a lot of time and headache!
EDIT
So, after re-reading the OP's question, I realize you want an entire list of associated data for the given violation of a given filename. In which case, you would switch the private String dataInside to something like private ArrayList<String> dataInside; which would allow you to associate as much data as you wanted, still inside that node, just inside of an arraylist. Also note, you'd have to switch up the getters/setters a little to accomodate a list, but that's not too bad.
You could use a custom class for a mapkey which contains the two fields filename and violation type. When doing so you need to implement equals() and hashCode() methods do ensure instances of that class can be used as key for map.
You can use TreeMap. TreeMap is sorted according to the natural ordering of its keys.
TreeMap<String, List<String>> map = new TreeMap<String, List<String>>();

how to use same string in two java files

Sorry for my bad English and for maybe stupid question but I'm new in Java.
I need use same string in 2 java files for example:
In first java file I've got code for sending emails, I've got string set to default email:
public String mail = new String ("lala#gmail.com");
and I use this string in code for send email:
email.addTo(mail);
In second java file something like set up where can user set new email address I want to have same string, connected with string in first java file. When user put new email String mail will be change to new email address and in email.addTo(mail); will be use this new address
How can I do this?
use Shared Preferences, you can store it as key-value Pair. value being your email and key can be any unique string which you want to identify it with.
I'm a bit confused with the question, but I'll take a stab at it. Basically, you would like to have one String in a given file be used in multiple locations. This is easily done using class-level variables and making them publicly accessible.
For example, in the file:
EmailObject.java
public class EmailObject {
public static final String mail = "lala#gmail.com";
// The rest of your code
}
Another file can access this like so:
OtherObject.java
public void sendEmail() {
EmailMessage email = new EmailMessage();
email.addTo(EmailObject.mail);
}
Note the static and final modifiers on the original. This ensures that you do not need an actual instance of EmailObject to access the string and it also ensures that the string is never modified accidentally by some other object.
There are, of course, other ways to do this, but this one matches your code the most. This is also a very "Java" solution. Android has other ways to share data (as indicated by the other answer).
The simplest way that I would not recommend is to have a public static field:
class A {
public static String commonString;
}
class B {
public void methodThatUsesString () {
// Do stuff with the string
Log.d("I have the string", A.commonString);
}
}
If you have two Activities, and one starts another, you can send data through Intents.
The forementioned SharedPreferences way is a good solution too, if the email address is a persistent thing, a preference if you will, and not just data reqired for an operation.
You can keep a reference of one instance of a class in the otherone, and access it's fields through it:
class A {
public String commonString;
}
class B {
private final A instaceOfA;
public B (A instanceOfA) {
this.instanceOfA = instanceOfA;
}
public void methodThatUsesString () {
// Do stuff with the string
Log.d("I have the string", instanceOfA.commonString);
}
}
Or even use a getter or setter if performance is not an issue.
Many answers depending on how the string will be used.
If it's a constant string, one that will never change, never use final static String
public final static String AUTHOR_MAIL = "lala#gmail.com";
Then you can use it in a static way wherever you want.
email.addTo(MyClass.AUTHOR_MAIL);
If this String will be used in different Activities you can not access it directly (you can not tell if the other Activity is still alive). You have to use Persistence Mechanisms such as SharedPreferences or directly send needed data in your Intent.
If it's in a helper class inside your Activity, you can just use mObject.mail to get it.

Categories

Resources