So recently I figured out how to work with JSON in java, and created code that writes, reads and updates information (mostly classes) to and from my JSON database. In my class 'Activity' I have a method that writes the class object to JSON:
public void createActivity() {
File file = database;
JSONObject newActivity = new JSONObject();
setRegDate(LocalDate.now());
try {
actID = IO.getJsonArray(file, "Activities").length() + 1;
} catch (Exception e) {
System.out.println("Exception: Could not set new activity ID.");
}
newActivity.put("userID", userID);
newActivity.put("actDate", actDate);
newActivity.put("regDate", regDate);
newActivity.put("actID", actID);
newActivity.put("description", description);
newActivity.put("coach", coach);
try {//Writes new user JSONObject to account file.
IO.putObjInArr(file, newActivity, "Activities");
} catch (Exception e) {
System.out.println("Exception: Creating activity failed.");
}
}
As the learning process continue, I have now added child-classes to my project. One child-class may contain the instance variables 'distance' and 'time'. There are several child-classes.
Now of course, I do not want to copy the above method to every child-class and there add the specific variables to it. I want all of this centralised in one parent-class.
I wonder, is it possible to somehow loop over all of the possible child-classes' variables, so that I can write those to JSON? Or are child-variables simply not visible to the parent, let alone if I don't specifiy to the parent which variables those might be?
For now, all that I can think of is to put all instance variables of the child class in a hashmap, send them as arguments to Activity.createActivity, and there loop over all the elements of the hashmap.
The problem you've faced has two main causes:
The functionality of this method is tightly coupled to the needs of a particular class. And as a consequence can be difficult to reuse in other classes.
The method itself violates the first principle of SOLID, the Single responsibility principle, which states that a class should have only one reason to change. But there's a whole lot of things happening in createActivity(): it reads JSON from a file, it alters the JSONobject, it updates the file.
Basically, all pieces of functionality that can be observed createActivity() should not be coupled to any class. Instead, this method can be split into several static methods, each representing a separate responsibility. And this method can be grouped into a Utility class.
That's how such class might look like:
public class JsonUtils {
private JsonUtils() {} // no way and no need to invoke the constructor of this class
public JSONObject readFromFile(Path path) throws IOException {
String json = Files.readString(path);
return new JSONObject(json);
}
public void updateJsonObject(Map<String, ?> map, JSONObject json) {
map.forEach(json::put);
}
public void writeToFile(Path path, JSONObject json) throws IOException {
Files.writeString(path,json.toString());
}
public void writeToFile(Path path, JSONObject json, OpenOption... options) throws IOException {
Files.writeString(path,json.toString(), options);
}
// other methods
}
Note: File class is legacy. The recommended alternative is to use Path from NIO API. And if you make use of Files utility class from NIO.2 as shown in the example above, it would immensely simplify code of IO-processing methods.
Related
I'm loading in classes from a JAR that implement an interface from a public API. The interface itself will remain constant but other classes associated with the API may change over time. Clearly once the API changes we will no longer be able to support implementations of the interface that were written with the old version. However some of the interface methods provide simple meta-data of type String that we can assume will never change and never rely on the other parts of the API that may change. I would like to be able to extract this meta-data even when the API has changed.
For example consider the following implementation that might be loaded in where Foo is the interface and Bar is an another class in the API. I want to call the name method even when the class Bar no longer exists.
class MyFoo implements Foo {
Bar bar = null;
#Override public String name() {
return "MyFoo"
}
}
As far as I can see the obvious approach is to override loadClass(String name) in my custom ClassLoader and return some "fake" class for Bar. The meta-data methods can be assumed to never create or use a Bar object. The question is how to generate this "fake" class when asked to load Bar. I've thought about the following approaches:
Simply return any old existing class. I've tried returning Object.class but this still results in a NoClassDefFoundError for Bar when I try to instantiate an instance of Foo.
Use ASM to generate the byte code for a new class from scratch.
Use ASM to rename some sort of empty template class to match Bar and load that.
Both 2. and 3. seem quite involved, so I was wondering if there was an easier way to achieve my goal?
Here is a class loader which will create a dummy class for every class it didn’t find on the search path, in a very simple way:
public class DummyGeneratorLoader extends URLClassLoader {
public DummyGeneratorLoader(URL[] urls, ClassLoader parent) {
super(urls, parent);
}
public DummyGeneratorLoader(URL[] urls) {
super(urls);
}
public DummyGeneratorLoader(
URL[] urls, ClassLoader parent, URLStreamHandlerFactory factory) {
super(urls, parent, factory);
}
static final byte[] template = ("Êþº¾\0\0\0002\0\n\1\7\0\1\1\0\20java/lang/Object"
+ "\7\0\3\1\0\6<init>\1\0\3()V\14\0\5\0\6\n\0\4\0\7\1\0\4Code\0\1\0\2\0\4\0"
+ "\0\0\0\0\1\0\1\0\5\0\6\0\1\0\t\0\0\0\21\0\1\0\1\0\0\0\5*·\0\b±\0\0\0\0\0\0")
.getBytes(StandardCharsets.ISO_8859_1);
#Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
try {
return super.findClass(name);
}
catch(ClassNotFoundException ex) { }
return new ByteArrayOutputStream(template.length + name.length() + 10) { {
write(template, 0, 11);
try { new DataOutputStream(this).writeUTF(name.replace('.', '/')); }
catch (IOException ex) { throw new AssertionError(); }
write(template, 11, template.length - 11);
}
Class<?> toClass(String name) {
return defineClass(name, buf, 0, count); } }.toClass(name);
}
}
However, there might be a lot of expectations or structural constraints imposed by the using code which the dummy class can’t fulfill. After all, before you can invoke the interface method, you have to create an instance of the class, so it has to pass verification and a successful execution of its constructor.
If the methods truly have the assumed structure like public String name() { return "MyFoo"; } using ASM may be the simpler choice, but not to generate an arbitrarily complex fake environment, but to parse these methods and predict the constant value they’d return. Such a method would consist of two instructions only, ldc value and areturn. You only need to check that this is the case and extract the value from the first instruction.
So, I have a program where many objects of several different classes need to read some (many) variables from an object of 'class X', to give it a name. A quick and simple way of doing this would be to make a singleton, which wouldn't be X itself but a class it access to. I've done this, and later on it started feeling dirty, and many seem to agree, so I'd like to change my design for this. I haven't found any ideas to replace this pattern, though, just "don't do it" and "pass the data around." I'd like my data to be read-only, though. I haven't found mention of any other patterns.
The best I've got to share these read-only variables, which seems perfectly fine to me, is to have a class SharedVars for the data to share, but in the form of an inner class. It's inside Data, which is an outer class that is able to modify SharedVars, encapsulating what's meant to be read-only for the other classes. Basically, any class that wants to read these variables needs a Data.SharedVars object:
public class Data {
public static class SharedVars {
private int encapsulatedData;
public int getData() {
return encapsulatedData;
}
}
// no one should touch this but Data:
static private SharedVars sharedData;
Data() {
sharedData = new SharedVars();
}
public SharedVars getDataRef() {
return sharedData;
}
// here's where this class (and only this class, whenever it's told)
// modifies the encapsulated data:
void manipulateData() {
sharedData.encapsulatedData = 5;
}
}
One of the classes that depends on this would take this form:
public class Client {
// This class can't access the data directly
// so it'll use Data's getter:
Data.SharedVars vars;
public Client(Data.SharedVars vars) {
this.vars = vars;
// vars.encapsulatedData = 5; // is not allowed, since the field is private (which is what I want)
}
public void go() {
// the proper way to get its hand on the data:
int data = vars.getData();
System.out.println("The data is " + data);
}
}
Main is not needed in this example, but I'll leave it here anyway:
public class Main {
static Data dataControl;
static Client client;
public static void main(String[] args) {
dataControl = new Data();
client = new Client(dataControl.getDataRef());
dataControl.manipulateData();
client.go();
}
}
Is this proper? Or, what are the risks here? Notice I don't want the objects to copy them for themselves, since they'll be changing all the time, and I don't entirely like the idea of having a reference to the 'class X' I've mentioned before.
Please avoid giving answers in Kotlin only and higher than Android 21.
I'm trying to build an API parser that makes use of class hierarchy logic to represent the API hierarchy itself. With this structure I am able to parse the API in an uncomplicated fashion and I was able to achieve this already, but I'd like to improve it further.
I'll begin explaining what I already have implemented.
This is an example URL that my app will receive via GET, parse and dispatch internally:
http://www.example.com/news/article/1105
In the app the base domain is irrelevant, but what comes after is the API structure.
In this case we have a mixture of commands and variables:
news (command)
article (command)
1105 (variable)
To establish what is a command and what is a variable I built the following class structures:
public class API {
public static final News extends AbstractNews {}
}
public class AbstractNews {
public static final Article extends AbstractArticle {}
}
public class Article {
public static void GET(String articleId) {
// ...
}
}
And I iterate through each class after splitting the URL while matching each command to each class (or subclass) starting from the API class. Until I reach the end of the split URL any matches that fail are stored in a separate list as variables.
The process is as follows for the example provided above:
Split URL each forward slash (ignoring the base domain)
/news/article/1105
List<String> stringList = [
news,
article,
1105
];
Iterate each item in the split list and match agains the API structured classes (the following is just a sample example, it is not 100% of what I currently have implemtend):
List<String> variableList = new ArrayList<>();
Class lastClass = API.class;
for (String stringItem : stringList) {
if ((lastClass = classHasSubClass(lastClass, stringItem)) != null) {
continue;
}
variableList.add(stringItem);
}
Once the end of the list is reached I check if the last class contains the request method (in this case GET) and invoke along with the variable list.
Like I said before this is working perfectly fine, but it leaves every class directly exposed and as a result they can be accessed directly and incorrectly by anyone else working on the project, so I am trying to make the hierarchy more contained.
I want to keep the ability to access the methods via hierarchy as well, so the following can still be possible:
API.News.Article.GET(42334);
While at the same time I don't want it to be possible to do the following as well:
AbstractArticle.GET(42334);
I have tried making each subclass into a class instance field instead
public class API {
// this one is static on purpose to avoid having to instantiate
// the API class before accessing its fields
public static final AbstractNews News = new AbstractNews();
}
public class AbstractNews {
public final AbstractArticle Article = new AbstractArticle();
}
public class Article {
public void GET(String articleId) {
// ...
}
}
This works well for the two points I wanted to achieve before, however I am not able to find a way to iterate the class fields in a way that allows me to invoke the final methods correctly.
For the previous logic all I needed to iterate was the following:
private static Class classHasSubClass(Class<?> currentClass, String fieldName) {
Class[] classes;
classes = currentClass.getClasses();
for (final Class classItem : classes) {
if (classItem.getSimpleName().toLowerCase().equals(fieldName)) {
return classItem;
}
}
return null;
}
But for the second logic attempt with fields I was not able to invoke the final method correctly, probably because the resulting logic was in fact trying to do the following:
AbstractArticle.GET(42334);
Instead of
API.News.Article.GET(42334);
I suspect it is because the first parameter of the invoke method can no longer be null like I was doing before and has to be the correct equivalent of API.News.Article.GET(42334);
Is there a way to make this work or is there a better/different way of doing this?
I discovered that I was on the right path with the instance fields, but was missing part of the necessary information to invoke the method correctly at the end.
When iterating the fields I was only using the Class of each field, which was working perfectly fine before with the static class references since those weren't instances, but now it requires the instance of the field in order to work correctly.
In the end the iterating method used in place of classHasSubClass that got this to work is as follows:
private static Object getFieldClass(Class<?> currentClass, Object currentObject, final String fieldName) {
Field[] fieldList;
fieldList = currentClass.getDeclaredFields();
for (final Field field : fieldList) {
if (field.getName().toLowerCase().equals(fieldName)) {
try {
return field.get(currentObject);
} catch (IllegalAccessException e) {
e.printStackTrace();
break;
}
}
}
return null;
}
With this I always keep an instance object reference to the final field that I want to invoke to pass as the 1st parameter (someMethod.invoke(objectInstance);) instead of null.
I want to design a system that allows the user to select from a list of file types to save the file as. I have a class named Word, and an interface named SaveFileType. Every filetype implements SaveFileType which has a saveFile() method. The idea is that when the 'programmer' wants to add a new filetype, none of the code in the application has to be changed.
This is the UML diagram I have made:
The problem that I am facing is the Word class doesn't have the list of all available file types, that I need to display to the user.
Some sample code below:
Word class:
public class Word {
SaveFileAs saveFileAs;
Document currentDocument;
public Word(Document currentDocument) {
this.currentDocument = currentDocument;
}
public void saveFile() {
// Print all available filetypes
// No actual file-saving logic is needed.
}
}
Word97 Class:
public class Word97 implements SaveFileAs {
#Override
public void saveFile(Document currentDocument) {
// Do some Java wizardry here.
System.out.println("Document named '" + currentDocument.getTitle() + "' has been saved as filetype 'Word97' " );
}
}
Main class:
public class Main {
public static void main(String[] args) {
Document notes = new Document("Notes", "This is a note.");
Word wordProgram = new Word(notes);
// saveFile should print out a list of all possible filetypes.
wordProgram.saveFile();
}
}
Strategy is for changing implementation at runtime, you cannot get all implementations. It would be the task of another class. Also you need somehow a method like setStrategy(Strategy) in your Word class, that's why you've chosen the pattern right?
For get all implementations, you could make use of ServiceLoader. I would add an enum in the picture.
So the example codes look like:
method in Word class:
void setSaveFileStrategy(AvailableStrategy strategy){
this.saveFileAs = strategy.strategy();
}
The enum:
enum AvailableStrategy{
Word97( Word97.class),
//.... once new strategy was introduced, you need add an entry here.
WordXml( WordXml.class);
private Class<saveFileAs> strategyClass;
AvailableStrategies(Class<saveFileAs> strategyClass) {
this.strategyClass = strategyClass;
}
saveFileAs strategy() throws IllegalAccessException, InstantiationException {
return strategyClass.newInstance() ;
}
}
I think you know how to get all enum instances (available strategies).
Note that codes were not compiled and tested, just for showing the idea. Exception handlings were ignored.
It would be bad if the Word class knew about all the types. It's the job of another class, even if word uses it. One solution would be to have a new class that maps a string extension to the strategy. And can enumerate those strategies:
public final class DocumentTypeMap implements Iterable<SaveFileAs> {
private final Map<String, SaveFileAs> docTypes = new HashMap<>;
public void register(String extension, SaveFileAs saveFileAs) {
docTypes.put(extension, saveFileAs);
}
public Iterator<SaveFileAs> iterator() {
return docTypes.values().iterator();
}
}
Usage:
DocumentTypeMap map = new DocumentTypeMap();
map.register(".doc", new Word97()); //etc.
Word word = new Word(map); //inject the dependency of a pre-configured map into the word class.
Then when the Word class needs the correct strategy during saving, it can use a method on DocumentTypeMap (not provided here) to get the correct one. I'm thinking that might be by extension.
If you want to be able to add a document type without changing any code, it means that the document type list has to be defined outside your code, in file like a property file and your code has to read the property file to know all available types.
Then you need to add in this property file which class implements how to save a specific document type and you implement a factory which instantiate a class given its name, and a class which associate the right instance according to the chosen type.
For the properties files, you can have entries like:
ext_1=.doc
ext_2=.xml
ext_3=.rtf
class_1=Word97
class_2=WordXML
class_3=RTF ...
A such file is easy to parse to know the types list and which class has to be used to save a document.
To know how to instantiate a class from its name, see the class Class and the method newInstance.
This is an "old way", maybe with injection is there a most up to date solution.
In your UML model, I would add the class which reads the properties file, the class which instantiates a class from its name, and the class which associate the right instance to Word. To model the properties file, maybe an instance objet may be use since a properties file is an instance of ResourceBundle.
I have the following design issue that I hope to get your help to resolve.
Below is a simplistic look at what the code looks like
class DataProcessor{
public List<Record> processData(DataFile file){
List<Record> recordsList = new ArrayList<Record>();
for(Line line : file.getLines()){
String processedData = processData(line);
recordsList.add(new Record(processedData));
}
}
private String processData(String rawLine){
//code to process line
}
}
class DatabaseManager{
saveRecords(List<Record> recordsList){
//code to insert records objects in database
}
}
class Manager{
public static void main(String[] args){
DatabaseManager dbManager = new DatabaseManager("e:\\databasefile.db");
DataFile dataFile = new DataFile("e:\\hugeRawFile.csv");
DataProcessor dataProcessor = new DataProcessor();
dbManager.saveRecords(dataProcessor.processData(dataFile));
}
}
As you can see, "processData" method of class "DataProcessor" takes DataFile object, processes the whole file, create Record object for each line and then it returns a list of "Record" objects.
My problem with "processData" method: When the raw file is really huge, "List of Record" objects takes a lot of memory and sometimes the program fails. I need to change the current desgin so that the memory usage is minimized. "DataProcessor" should not have direct access to "DatabaseManager".
I was thinking of passing a queue to "processData" method, where one thread run "processData" method to insert "Record" object in the queue, while another thread remove "Record" object from the queue and insert it in database. But I'm not sure about the performance issues with this.
Put the responsibility of driving the process into the most constrained resource (in your case the DataProcessor) - this will make sure the constraints are best obeyed rather than forced to the breaking point.
Note: don't even think of multithreading, it is not going to do you any good for processing files. Threads will be a solution if your data comes over the wire, when you don't know when your next data chunk is going to arrive ad perhaps you have better things to do with your CPU time than to wait "until cows come home to roost" (grin). But with files? You know the job has a start and an end, so get on with it as fast as possible.
class DataProcessor{
public List<Record> processData(DataFile file){
List<Record> recordsList = new ArrayList<Record>();
for(Line line : file.getLines()){
String processedData = processData(line);
recordsList.add(new Record(processedData));
}
}
private String processData(String rawLine){
//code to process line
}
public void processAndSaveData(DataFile dataFile, DatabaseManager db) {
int maxBuffSize=1024;
ArrayList<Record> buff=new ArrayList<Record>(maxBuffSize);
for(Line line : file.getLines()){
String processedData = processData(line);
buff.add(new Record(processedData));
if(buff.size()==maxBuffSize) {
db.saveRecords(buff);
buff.clear();
}
}
// some may be still unsaved here, less that maxBuffSize
if(buff.size()>0) {
db.saveRecords(buff);
// help the CG, let it recycle the records
// without needing to look "is buff still reacheable"?
buff.clear();
}
}
}
class Manager{
public static void main(String[] args){
DatabaseManager dbManager = new DatabaseManager("e:\\databasefile.db");
DataFile dataFile = new DataFile("e:\\hugeRawFile.csv");
DataProcessor dataProcessor = new DataProcessor();
// So... do we need another stupid manager to tell us what to do?
// dbManager.saveRecords(dataProcessor.processData(dataFile));
// Hell, no, the most constrained resource knows better
// how to deal with the job!
dataProcessor.processAndSaveData(dataFile, dbManager);
}
}
[edit] Addressing the "but we settled on what and how, and now you are coming to tell us we need to write extra code?"
Build an AbstractProcessor class and ask your mates just to derive from it.
class AbstractProcessor {
// sorry, need to be protected to be able to call it
abstract protected Record processData(String rawLine);
abstract protected Class<? extends Record> getRecordClass();
public void processAndSaveData(DataFile dataFile, DatabaseManager db) {
Class<? extends Record> recordType=this.getRecordClass();
if(recordType.equals(MyRecord1.class) {
// buffered read and save MyRecord1 types specifically
}
else if(recordType.equals(YourRecord.class)) {
// buffered read and save YourRecord types specifically
}
// etc...
}
}
Now, all they need to do is to "code" extends AbstractProcessor and make their processData(String) protected and write a trivial method declaring its record type (may as well be an enum). It's not like you ask them a huge effort and makes what would have been a costly (or even impossible, for a TB input file) operation a "as fast as possible one".
You should be able to use streaming to do this in one thread, one record at a time in memory. The implementation depends on the technology your DatabaseManager is using.