I have a code:
abstract void run();
public void start() {
Logger log = Logger.getLogger(Test.class.getName());
try {
run();
} catch (Exception e) {
log.warn(e.getMessage());
}
}
I can execute start() for example:
object1.start();
object2.start();
object3.start();
How can I check in start() which object (name object) started the method start()?
There is no automatic way to do this; objects in Java don't have to have a name.
One solution is:
public void start(String name) {
Logger log = Logger.getLogger(name);
}
This works because a logger can have an arbitrary name. Many loggers use the class's name because that's a simple + automatic way to name loggers. But that's not necessary.
Assuming you're trying to get "object1", "object2" and "object3" as the names (it's not clear), there are two things you ought to be aware of:
Those are variables, not objects. Multiple variables with different names could refer to the same object.
Objects don't generally have names - you can add your own name field, but you'll have to do that explicitly.
new Exception().getStackTrace()[1]
see StackTraceElement
If you mean to get the string "object1": this is logically not sensible. This is the name of a variable not the object it refers to, and does not exist at runtime. In fact, the compiler may optimize it away completely. Plus, it is ambiguous:
Consider the following code:
object2 = object1;
object2.start();
Should the instance now see the name "object1" or "object2"? It is both!
If you want your objects to have a "name", use a self-managed field to store it.
object1.setName("object2");
or do the same in the constructor:
MyObject object1 = new MyObject("object1");
You can't get the name of the variable at runtime, if that is what you want
I would start the Log outside the start() method
Logger log = Logger.getLogger(object1);
object1.start(log);
Then your start() method will look like this:
public void start(Logger log) {
try {
run();
} catch (Exception e) {
log.warn(e.getMessage());
}
}
Or, if you can't change the start() signature:
Logger log;
public void setLogger(Logger log){
this.log = log;
}
public void start() {
try {
run();
} catch (Exception e) {
log.warn(e.getMessage());
}
}
Then:
Logger log = Logger.getLogger(object1);
object1.setLogger(log);
object1.start();
Related
Let's say I have an abstract class, called Logger:
public abstract class AbstractLogger {
public enum Levels {
DEBUG, INFO, WARNING, ERROR
}
public void debug(String message) {
Levels level = Levels.DEBUG;
log(level, message);
}
public void info(String message) {
Levels level = Levels.INFO;
log(level, message);
}
public void warning(String message) {
Levels level = Levels.WARNING;
log(level, message); }
public void error(String message) {
Levels level = Levels.ERROR;
log(level, message); }
public void log(Levels level, String message) {}
}
And I also have classes that inherit this class, such as FileAppenderLogger:
public class FileAppenderLogger extends AbstractLogger {
private final Path logPath;
public FileAppender(Path logPath) {
this.logPath = logPath;
createLogFile();
}
private void createLogFile() {
try {
File logFile = new File(logPath.toString());
if (logFile.createNewFile()) {
System.out.println("File created: " + logFile.getName());
} else {
System.out.println("File already exists.");
}
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
#Override
public void log(Levels level, String message) {
try {
FileWriter myWriter = new FileWriter(this.logPath.toString());
myWriter.write(message+"\n");
myWriter.close();
System.out.println("Successfully wrote to the file.");
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
}
}
#Override
public void debug(String message) {
super.info(message);
}
#Override
public void info(String message) {
super.info(message);
}
#Override
public void warning(String message) {
super.warning(message);
}
#Override
public void error(String message) {
super.error(message);
}
}
Now, let's say I need to extend Logger to support new Log level, such as "FATAL", and also extend its children, such as FileAppenderLogger to support it, without modify any of those classes, only extend them.
what could be the best practice for that (if I still want to preserve non generic methods such as ".info(String s)" or ".debug(String s))?
What design pattern may I use here?
I'm open for changes regard this problem.
Thank you!
Simply add it to AbstractLogger:
public abstract class AbstractLogger {
public enum Levels {
DEBUG, INFO, WARNING, ERROR, /* added */ FATAL,
}
public void fatal(String message) {
log(Levels.FATAL, message);
}
}
Given that the types that extend AbstractLogger all already implement the log method, then 'things will just work' - possibly some of the implementations cannot deal with the fact that a new log level has now appeared. Assuming they were appropriately programmed, they'll throw. Your FileAppenderLogger class, for example, would just continue to work without requiring any change or even recompilation.
The key design pattern to make this work is that all those non-generic methods such as .error(x) are light wrappers that all send the data to a single method that does the real work - log. But, you already do that.
NB: Reinventing the wheel is a bad idea. Logging frameworks already exist, use an existing one instead.
NB2: Idiomatic java dictates you call your enum types the singular - it should be Level, not Levels. The type name describes, well, a type name. It's called String, not Strings, because an instance of java.lang.String represents one string. The class itself represents all strings, but that doesn't mean it should be called Strings. Similarly, an instance of the Levels enum represents a single level. Hence, it should be named Level, not Levels.
Instead of using enum for level, you can make class LogLevel and make classes that extend it, for example LogLevelError, LogLevelFatal, then in log method: this.logLevel.log(message);. Of course, it look strange, but this is the way I see to add new log levels. Also, as said by #rzwitserloot :"NB: Reinventing the wheel is a bad idea. Logging frameworks already exist, use an existing one instead". They are much faster, optimized, and 'time-tested'.
You can't add more values to your enum, that's not possible in java. I would suggest to either use a String for levels, or declare your own Level class, so you can add more levels.
public class Level {
private final String levelName;
//getter, etc.
}
To extend the functionality of your AbstractLogger, without modifying it, you can wrap it in another class and declare the additional methods, fatal() in this case.
public class ExtendedLogger extends AbstractLogger {
private final AbstractLogger abstractLogger;
public ExtendedLogger(AbstractLogger abstractLogger) {
this.abstractLogger = abstractLogger;
}
#Override
public void debug(String message) {
abstractLogger.debug(message);
}
//info, warning and rest of methods
#Override
public void log(Levels level, String message) {
abstractLogger.log(level, message);
}
public void fatal(String message) {
//implement
}
}
First: logger libraries are numerous, and the first reform was the introduction of java.util.Logger to unify things a bit. Still not the dead of the other logging libraries.
Then came - especially for libraries - the underestimated System.Logger: a Logger façade that can be discover logging implementations. This allows publishing a library, use Logging, but leave the actual logging library choice to the library user.
So in that context meddling in class hierarchies and enum constants is counter-productive to say the least.
What you can do is a specific configuration, say for some packages, implement a specific file handler (FileHandler, Handler), and reserve ERROR for your own FATALISH when using *Exception classes or such.
Though seemingly simple, using FileWriter in the Logger child was not intended to be done as such. You should leave it to configuring the usage to your own Handler class.
Unfortunately the solution does not exist. You'll better write a prototype to test your specific configuration.
I have a singleton class
public class SingletonText {
private static final CompositeText text = new CompositeText(new TextReader("text/text.txt").readFile());
public SingletonText() {}
public static CompositeText getInstance() {
return text;
}}
And TextReader constructor that could throw FileNameEception
public TextReader(String filename) throws FileNameException{
if(!filename.matches("[A-Za-z0-9]*\\.txt"))
throw new FileNameException("Wrong file name!");
file = new File(filename);
}
How can I rethrow it to main and catch it there?
Main class
public class TextRunner {
public static void main(String[] args) {
// write your code here
SingletonText.getInstance().parse();
System.out.println("Parsed text:\n");
SingletonText.getInstance().print();
System.out.println("\n\n(Var8)Task1:");
SortWords.sortWords(SingletonText.getInstance().getText().toString(), "^[AEIOUaeiou].*", new FirstLetterComparator());
System.out.println("\n\n(Var9)Task2:");
SortWords.sortWords(SingletonText.getInstance().getText().toString(), "^[A-Za-z].*", new LetterColComparator());
System.out.println("\n\n(Var16)Task3:");
String result = SubStringReplace.replace(SingletonText.getInstance()
.searchSentence(".*IfElseDemo.*"), 3, "EPAM");
System.out.println(result);
}}
Static block is executed only when class is loaded for the first time, so you can have something as below which will allow you to re-throw the exception. In you main method, you will surround getInstance() invocation in a try-catch block and then in catch you can do whatever you are looking for.
In case of exception, this exception will be thrown and re-thrown (from you static block) only once, at time of class loading. What #Alexander Pogrebnyak has said is also true.
Looking at the code you have provided, since you are always reading text/text.txt files so below approach will work. In case you are looking to read different files and then re-throwing exception then that becomes all together a different story, and you hadn't asked that part neither the code you have provided shows the same. In any case, if that's what you are looking for then:
you need to create a singleton object of your CompositeText class.
create a setter method will create an object TextReader class using the file name string passed.
that setter method will have the try-catch block, and in the catch block you will re-throw the exception so that you can catch again in main method.
P.S.: since static blocks are executed only once when class is loaded and class is loaded only once per JVM (until you have custom class loaders and overriding the behavior) so this ensures that this singleton is thread-safe.
Code:
public class SingletonText {
private static CompositeText text = null;
static{
try {
text = new CompositeText(new TextReader("text/text.txt").readFile());
} catch (FileNameException e) {
// TODO: re-throw whatever you want
}
}
public SingletonText() {}
public static CompositeText getInstance() {
return text;
}
}
try to lazy initialze the singleton.
something like this:
public class SingletonText {
private static CompositeText text;
public SingletonText() {
}
public static CompositeText getInstance() {
if (text ==null) {
text = new CompositeText(new TextReader("text/text.txt").readFile());
}
return text;
}
}
Also, you need to declare the constructor private, and if it multi-threaded application you need to synchronized the new statement with double check locking. see this in wiki:
https://en.wikipedia.org/wiki/Double-checked_locking#Usage_in_Java
Enjoy..
You will get java.lang.ExceptionInInitializerError when your singleton static initializer will fail.
As a cause it will have your FileNameException.
If you don't do anything, default exception handler will print the whole stack trace to standard error.
Lets say I have class Foo:
public class Foo {
// ...
}
I want to get its constant pool as a byte array from another class. i.e:
public class Bar {
void butts() {
byte[] fooConstantPool = Foo.class.getConstantPool();
// ...
}
}
Class#getConstantPool is not part of the standard API. Is there any consistent way I can get another class' constant pool?
You can get it as sun.reflect.ConstantPool object via reflection like this:
import sun.reflect.ConstantPool;
public class Bar {
private static final Method getConstantPool;
static {
try {
getConstantPool = Class.class.getDeclaredMethod("getConstantPool");
getConstantPool.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
void butts() {
ConstantPool constantPool = (ConstantPool) getConstantPool.invoke(Foo.class);
// ...
}
}
but I'm not sure how to get it as byte array. You can try to serialize it :)
You can scan your class loader to find the class's location on disk, then use a framework like BCEL to analyze it.
I have a website demonstrating this, but StackOverflow says I am not allowed to post links to it.
I never really thought about this before but looking at the following code
public class SomeJavaProgram {
private static String runMe() {
throw new RuntimeException("hi tadsfasdf");
}
private static String name = runMe();
public static void main(String[] args) {
System.out.println("hi there.");
}
}
I never did statics like this in a main before but then I entered scala, and if you have subclasses that start adding defs, exceptions can be thrown before main is even called.
So, in java(not scala), is there a way to catch these exceptions(if I am the superclass and subclasses end up having a static field that throws an exception or static initializer block)....how can I catch all these?
I of course do rely on ONE single definition not throwing which is the
private Logger log = createLoggerFromSomeLoggingLib();
But after that, ideally I would want all exceptions to be logged to the logged file rather than stderr.
That said, I am glad I have always kept the stderr/stdout files along with my logging files now.
Use the static initializer:
private static String name;
static {
try {
name = runMe();
} catch (RuntimeException e) {
// handle
}
}
I have a two classes UpObj and DownObj
public class UpObj {
public UpObj() {
System.out.println("Load UpObj ");
}
}
public class DownObj extends UpObj {
public DownObj() {
System.out.println("Load DownObj ");
}
}
public class Caller {
UpObj obj;
public Caller(UpObj obj) {
this.obj = obj;
System.out.println("!!!");
}
}
public class GNUMakeFile {
/**
* #param args
*/
public static void main(String[] args) {
DownObj iView = new DownObj();
Class<?> iViewClass = iView.getClass();
Class<?> clazz;
try {
clazz = Class.forName("bla.bla.bla.Caller");
Constructor<?> ctor = clazz.getDeclaredConstructor(iViewClass);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
}
So, I want upcast my child type DownObj to parent UpObj in Caller constructor.
I think this is possible with help generics. Something like this .
Anybody know how exactly this use.
Thanks.
You shouldn't really be using Class.getConstructor() with the runtime type of what you want to pass to it – the method works off the formal parameters.
If you need to search for a constructor that matches some objects that you have, you'll have to loop over getConstructors(), inspect the formal parameters of each constructor, and check whether you found a suitable signature using Class.isAssignableFrom(). I don't think there's a convenient way to have the reflection API do overload resolution for you.
(Alternatively, rethink your approach so messing with reflection is no longer necessary.)
There is no standard way doing it. Try to google for some solutions, e.g. http://www.xinotes.org/notes/note/1329/ or How to get parameter types using reflection? . As I remember the Spring and some other libraries have similar util functions to do it. Do you use the Spring?
I didn't really understand the problem - upcasting is normally not needed.
but it seams like the problem is to get the upper class of the object,
if use the getSuperclass method:
Constructor<?> ctor = clazz.getDeclaredConstructor(iViewClass.getSuperclass());
Documentation: getSuperclass()