Why will the following not work? Is it not possible to cast like this?
I get the error: java.lang.ClassCastException: java.io.File cannot be cast to MyMusicFile
public class MyMusicFile extends java.io.File
{
public MyMusicFile(String pathname)
{
super(pathname);
}
public String artist;
public String album;
public String track;
public String year;
}
main(String[] args)
{
File file = new File("/home/1.txt");
MyMusicFile mmf = (MyMusicFile) file;
}
If MyMusicFile extends File, then MyMusicFile is also a File, but that doesn't make File a MyMusicFile. If you list all the super classes for each class, you'd get:
File: java.lang.Object
MyMusicFile: java.io.File, java.lang.Object
And you can assign any type to it's type or any other super type (say Object to File, or File to MyMusicFile).
You can think of it like this: MyMusicFile has all the fields and methods like File, plus some extra ones. So it's safe to assign an instance of MyMusicFile to a File because it will work (has all the required stuff), but a File doesn't have all the stuff MyMusicFile has (that extra stuff is missing), so it wouldn't work.
No, it's not possible. What would you get if you try to cast a Horse to a Car? You may only cast something to something it actually is. For example, the following is OK:
Object o = new Integer(345);
Integer i = (Integer) o;
Number n = (Number) o;
Because the object that the o variable references is an Integer, which is also a Number, which is also an Object.
The other answers are entirely correct, but also I should point out that some classes in Java are not designed for subclassing for most user needs, and java.io.File is one of these. You just create a File object that refers to your desired file. The point of subclassing is to add extra behavior to the original class, and that's not generally not necessary for a File.
As others have explained, your code does not work because while MyMusicFile is a File, the inverse is not true (File is not a MyMusicFile). You should change your design from extension (is-a) to aggregation (has-a). Something like this:
public class MyMusicFileReader {
private File musicFile;
public MyMusicFileReader(File file) {
super();
musicFile = file;
}
public void load() {
// load your info here
}
}
public static void main(String[] args) {
File file = new File("/home/1.txt");
MyMusicFileReader mReader = new MyMusicFileReader(file);
mReader.load();
}
Related
Since I'm a newbie, I would like to know if there is a better way to code this.
Let say we have batch (spring) where we have downloader/processor/mapper/writer for every type of file we receive since we have customized logic for each file type. X number of Mapper , X number of processor for X number of file types.
Currently looking into templatize the code so not much changes may be required when new type is introduced. Below is my idea. so let say mapper, we have different objects for different file types and all of them will be converted to object of Class CustomObject as below. mapper bean in sample spring context
bean id = "file1Mapper" class = "com.filemapper.file1Mapper"
and it invokes file1Mapper class which has mapping logic. Same for other files.
This is what I'm coming up with to avoid all those file1mapper, file2mapper...... instead one generic mapper which does all together, but looking for better solutions,
public class GMapper{
public <T> CustomObject map(T item){
CustomObject customObject = new CustomObject()
.WithABCDetails(getABCDetails(item));
}
private <T> XYZDetails getABCDetails(T item) {
ABCDetails details = new ABCDetails();
if( item instanceof A){
A a = (A)item;
// read a and map it to ABCDetails object
}
if( item instanceof B){
B b = (B)item;
// read b and map it to ABCDetails object
}
...
...
// repeat this if loop for mapping all file types.
return details;
}
}
Sample jsons
class ABCDetails{
// JsonProperty
Object1 ob1;
Object2 ob2;
Integer d;
}
class Object1{
// JsonProperty
Object3 ob3;
String abc;
String def;
}
class Object2{
// JsonProperty
String ab;
Integer e;
}
class A{
// JsonProperty
String e;
String d; // ex, this is mapped to Object 2 String "ab"
}
This does't look so professional and I believe there might be better ways to do it. Can someone please share an example or explanation on how can this code be made better. I also reading Functional interface to see if that could help.
Thanks in advance.
It is impossible to understand what you need. So I will give some common advice.
Format your code - use tabs/spaces to indent.
Do not put capital letters together - replace ABCDetails with AbcDetails. No one cares how real world name looks like.
Do not write meaningless comments - say no to // JsonProperty
Name variables so that someone can understand what they are supposed to store - avoid {Object1 ob1; Object2 ob2; Integer d;}
Do not write if ... else if ... else if ... or case when ... since this scales badly. Use Map. Examples below.
And a general solution to your problem: use plugin architecture - the best thing (and maybe the only thing) that OOP can offer. Just make all your processors implement common interface. And to work with plugins use dispatcher pattern.
First create all processors.
public interface FileProcessor {
String extension();
void process(String filename);
}
#Component
public final class CsvFileProcessor implements FileProcessor {
public String extension() {
return "csv";
}
public void process(String filename) {
/* do what you need with csv */
}
}
#Component
public final class JsonFileProcessor implements FileProcessor {
public String extension() {
return "json";
}
public void process(String filename) {
/* do what you need with json */
}
}
Then inject them into your dispatcher. Do not forget to process errors, for example, some files may not have suffix, for some files you will not have processor, etc.
#Component
public final class FileDispatcher {
private final Map<String, FileProcessor> processorByExtension;
#Autowired
public FileDispatcher(List<FileProcessor> processors) {
processorByExtension = processors.stream().collect(Collectors.toMap(p -> p.extension(), p -> p));
}
public void dispatch(String filename) {
String extension = filename.split("//.")[1];
processorByExtension.get(extension).process(filename);
}
}
Now if you need to support new file format you have to add only one class - implementation of FileProcessor. You do not have to change any of already created classes.
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.
When I run the following code to save a JSON:
String regionObject = this.gson.toJson(parentRegion);
JsonFileInputOutput.saveObjectToTextFile(regionObject,
"./tests/model/util/test_saveRegionObject.txt");
and after that I reopen the created .txt file:
public void test_openRegionObject() throws IOException {
String regionAsString = JsonFileInputOutput
.openObjectInTextFile("./tests/model/util/test_saveRegionObject.txt");
Gson gson = new Gson();
Region LGNRegion = gson.fromJson(regionAsString, Region.class);
System.out.println(LGNRegion.toString());
}
it works perfectly fine.
However, when I try the second snippet of code into a different class that does not contain the first one I get the following error:
java.lang.RuntimeException Failed to invoke public model.MARK_II.Cell() with no args
Cell is a custom class that is used inside Region class. Here is the implementation of the Cell class:
public abstract class Cell {
protected boolean isActive;
public Cell() {
this.isActive = false;
}
public boolean getActiveState() {
return this.isActive;
}
public void setActiveState(boolean isActive) {
this.isActive = isActive;
}
}
My question is how can I fix this exception so that I can read a proper serialized JSON as the one I create with first snippet of code.
Two questions here.
Why I get the exception? This is simple to answer: your Cell class (or better your subclass of Cell class since Cell is abstract) has no a constructor without parameters. Maybe it has a constructor with one or more parameters.
Why I can't open a generic file? Difficult to say without showing us the file. It's sure that if you save a Json serialization into a file and just open it you have no error. My best guess is this: when you serialize and save you have not Cell subclasses inside (maybe member variables are nulls), whenever you open another file, maybe Cell subclasses are defined and so answer to 1. applies.
Say that i have a boolean property that should represent the fact that a specific file inside a specific path exists or not.
Here is some code:
class SomeClass {
protected static final File FILE_TO_TEST = new File("test.canc.me");
//My javafx property
public ReadOnlyBooleanPropertyBase fileExistingProperty = new ReadOnlyBooleanPropertyBase() {
#Override public boolean get() {
return FILE_TO_TEST.exists();
}
#Override public Object getBean() { return null; }
#Override public String getName() { return ""; }
};
//old style property property
public boolean isFileExisting() {
return fileExistingProperty.get();
}
Ok. The fact is that this property is read only since it cannot be set, its value depends of the "external" condition represented by the file to be existent in the application home.
Yet, i need to refresh the property, that is look again to see if the file still exsist or not, and raise change and invalidation events accordingly.
I could easily add a refresh method to the property class, but in order to call it, i would have to create an inner class and not just an anonyous one.
And i would need an anonymous class for each different type of read-only-yet-refreshable property, that is boolean, String, Integer etc.
The question is: is there a more convenient way to accomplish this?
i would have to create an inner class and not just an anonyous one.
I would go down this approach rather than try to create a bunch of anonymous inner classes.
And i would need an anonymous class for each different type of read-only-yet-refreshable property, that is boolean, String, Integer etc.
Use generics - that's what they're designed for! Create a ReadOnlyRefreshableProperty<T>, then the return types and parameters of the relevant methods all use T as their type, removing the need for a separate class for each type.
Is it possible to get the class type from inside the static initialization block?
This is a simplified version of what I currently have::
class Person extends SuperClass {
String firstName;
static{
// This function is on the "SuperClass":
// I'd for this function to be able to get "Person.class" without me
// having to explicitly type it in but "this.class" does not work in
// a static context.
doSomeReflectionStuff(Person.class); // IN "SuperClass"
}
}
This is closer to what I am doing, which is to initialize a data structure that holds information about the object and its annotations, etc... Perhaps I am using the wrong pattern?
public abstract SuperClass{
static void doSomeReflectionStuff( Class<?> classType, List<FieldData> fieldDataList ){
Field[] fields = classType.getDeclaredFields();
for( Field field : fields ){
// Initialize fieldDataList
}
}
}
public abstract class Person {
#SomeAnnotation
String firstName;
// Holds information on each of the fields, I used a Map<String, FieldData>
// in my actual implementation to map strings to the field information, but that
// seemed a little wordy for this example
static List<FieldData> fieldDataList = new List<FieldData>();
static{
// Again, it seems dangerous to have to type in the "Person.class"
// (or Address.class, PhoneNumber.class, etc...) every time.
// Ideally, I'd liken to eliminate all this code from the Sub class
// since now I have to copy and paste it into each Sub class.
doSomeReflectionStuff(Person.class, fieldDataList);
}
}
Edit
I picked the accepted answer based on what applied best to my problem, however it seems to me that all three of the current answers have their merits.
No, it's not possible without grabbing the stacktrace (which is imo nastier than your initial approach and for which I would in any way prefer Thread#getStackTrace() above new Exception()).
Rather do that job in a non-static initializer (or the default constructor) of the abstract class where you check the initialized status.
public abstract class SuperClass {
{
if (!isInitialized(getClass())) {
initialize(getClass());
}
}
}
The called methods in turn can be safely static.
yes, I use this often to initialize a static Log variable :
e.g. :
public class Project implements Serializable, Cloneable, Comparable<Project> {
private static final Logger LOG = LoggerFactory.getLogger(Project.class);
...
To get a class at runtime, you could do something along the lines of
public class Test {
public static void main(String[] args) {
try{
throw new Exception();
}
catch(Exception e){
StackTraceElement[] sTrace = e.getStackTrace();
// sTrace[0] will be always there
String className = sTrace[0].getClassName();
System.out.println(className);
}
}
}
Not pretty but will do the job (ripped from http://www.artima.com/forums/flat.jsp?forum=1&thread=155230).
This means you still make a call from the subclass (so is in the stack trace), but you don't need to include the XXX.class as an argument.