I am not sure if that is possible but I have a old java application projects which have 1000+ java files. I am trying to add log4j support to the application which require me to add
public static Logger logger = Logger.getLogger(MyClass.class.getName());
in every file.
Is there any way I can perform the operation using eclipse. I have tried source->format but that is not allowing me to add the line. Do I have to open every file and add that line?
You could make use of templates in eclipse, but in this case, you need to edit each file and add it.
Update :
Save following content in some file-named with extension ".xml"
<?xml version="1.0" encoding="UTF-8" standalone="no"?><templates><template autoinsert="true" context="java-members" deleted="false" description="adds the logger statement" enabled="true" name="logger">public static Logger logger = Logger.getLogger(${enclosing_type}.class.getName());</template></templates>
Press CTRL+3, Type - "templates" and choose for Templates- Java Editor as shown below
Import the file from menu from right as shown below
now go to any of your file and type "logger"in your class file and do CTRL+space , quick assist will show you the "logger" template
as shown below
and your logging statement will appear, with your class in which you are editing as shown below
You can do it programatically. Start with a filter for all your .java:
public class FileExtensionFilter implements FilenameFilter {
private Set<String> filteredExtensions;
public FileExtensionFilter() {
filteredExtensions = new HashSet<String>();
}
#Override
public boolean accept(File dir, String name) {
boolean accept = true;
for (String filteredExtension:filteredExtensions) {
accept = accept && !name.endsWith(filteredExtension);
}
return accept;
}
public void addFilteredExtension(String extension) {
filteredExtensions.add(extension);
}
}
Then you can look for the file using a recursive method:
public Set<String> searchFileBasedOnExtension(File file) {
Set<String> extensions = new HashSet<String>();
if (file.isDirectory()) {
for (File f : file.listFiles(fileExtensionFilter)) {
extensions.addAll(checkForExtensions(f));
}
} else {
String extension = file.getName().substring(Math.max(file.getName().lastIndexOf('.'),0));
extensions.add(extension);
fileExtensionFilter.addFilteredExtension(extension);
}
return extensions;
}
Then based on the set you receive, you can iterate it, read the file to find the position to add the "import" and also find the class name, and save it into a variable to replace it for each file, since each file represents a different class.
Sample:
for (String s : setWithFileNames) {
// Use BufferedReader to read the file, save the content in a String, then look inside the String the classname and the first import position.
// Use bufferedWriter to re-write the file with the changes you made.
}
Hope it gives you a hand with your requirement. Best regards.
Opening each file and adding this line would be tedious.
I am not sure if Eclipse has such thing.
But I would suggest to go for a shell script or a Java function to do this.
Read each file.
Search for the first '{' character.
Insert the logger statement in the line next to that.
You can get the class name from the file name.
I know this might not be the best solution for you.
Hope this helps.
If you have notepad ++ you can do it. Use the find replace feature for a direcory using regular expressions.
so a line starting with public class need to be replaced by the line and another line with the log statement.
Another suggestion is to use AspectJ. AspectJ is an extension to Java that allows you to systematically weave in extra functionality to existing classes. You would first need to install AJDT (AspectJ development tools). Then you need to create an Aspect like this:
aspect LoggingAspect {
before (Object thiz) : execution(public * *(..)) && this(thiz) {
Logger logger = Logger.getLogger(thiz.getClass().getName());
logger.log("Something");
}
}
The aspect above will log every execution of a public method of one of the classes that you compile. You can certainly tweak this in many ways. Logging is one of the simplest things that AspectJ can do. The nice thing about going down this path is that you can easily enable/disable logging from your project by commenting out 4 lines.
The main AspectJ website. And the AspectJ programming guide is a good place to start with AspectJ.
You can run the below command to add any line on the specific line number, Just provide the folder name it will search all the subfolders with the file extension as .java and add the line on the specific position:
find <Folder Path> -name "*.java" -exec sed -i '1i<Text: You want to add>' {} \;
Related
I need to execute a java jar file from Spoon.
The program has only one class, and all I want is to run it with or without parameters.
The class is named "Limpieza", and is inside a package named:
com.overflow.csv.clean
I have deploy the jar to:
C:\Program Files (x86)\Kettle\data-integration\lib
And from a Modified JavaScriptValue step, I am calling it this way:
var jar = com.everis.csv.clean.Limpieza;
This is not working at all, is there a way around to make it work?
Also would be nice to have a way to see the logs printed by the program when it runs.
I am not getting any error when I run the transformation.
Thanks.
Check the blog below:
https://anotherreeshu.wordpress.com/2015/02/07/using-external-jars-import-in-pentaho-data-integration/
Hope this might help :)
Spoon will load any jar files present in its
data-integration\lib
folder and its subfolders during startup, so if you want to access classes from a custom jar, you could place the jar here.
So you need to create a custom jar and place the jar in
data-integration\lib
location.
While calling a custom class in "Modified Java Script Value" or in "User Defined Java Class step" you should call with fully qualified name. For example var jar = com.everis.csv.clean.Limpieza.getInstance().getMyString();
Note: After placing the jar, make sure you restart the Spoon.
If still does not work please attach the Pentaho.log (data-integration-server/logs/Pentaho.log) and catalina.out(data-integration-server/tomcat/logs) logs
The answer was to create a User Defined Java Class (follow the guide Rishu pointed), and here is my working code:
import java.util.*;
import com.everis.csv.Cleaner;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
Cleaner c = new Cleaner();
c.clean();
// The rest of it is for making it work
// You will also need to make a Generate Rows step that inputs a row to this step.
Object[] r = getRow();
if (r == null) {
setOutputDone();
return false;
}
r = createOutputRow(r, data.outputRowMeta.size());
putRow(data.outputRowMeta, r);
return true;
}
i have a ready to use .jar file and want to know if its possible to extract and rename the packages?
so when usually i start the .jar file with:
java -cp myFile.jar com.codehelper.demo.Main
i want to rename the "codehelper" in it to something different that i can run it by
java -cp myFile.jar com.NEW_NAME.demo.Main
i tried to decompile all files, add it to the folderstructure with renamed "codehelper" path and compile it again but it didnt work. i also renamed all the package includes in each file like
import com.codehelper...
so is my goal unreachable or can i do this? and if someone can explain me how to do, it will be very nice.
thank you and sory for my poor english
edit: it seems the only file i cant compile is a file containing this switch case.
private int priotiryLevel(DiscoveryInfoBehave info)
{
int ret = 0;
switch (1.$SwitchMap$com$peerialism$natcracker$common$GatewayDevice$GatewayType[info.getNatDevice().getGatewayType().ordinal()])
{
case 1:
ret = 0;
break;
case 2:
ret = 4;
break;
case 3:
ret = 5;
break;
}
return ret;
}
i tried also to rename the specific word inside this switch case but no effort.
Write a new wrapper class:
package com.NEW_NAME.demo;
public class Main
{
public static void main(String[] args)
{
com.codehelper.demo.Main.main(args);
}
}
compile it and add it to the jar. You can now invoke it as:
java -cp myFile.jar com.NEW_NAME.demo.Main
and it will silently dispatch to the real implementation.
This is not possible generally. If you rename some files, Java wont be able to find them (public class name must be same as file name). You can rename file with main class and call it as #Joe suggested in his answer. But if you rename somthing else, it will stop working. There could be cals to those classes in code. Same goes for the "codehelper" name. You can not remove it from code. Even if you remove it from one file, anyone will still be able to see this somewhere else in the code.
Rename directory is the same as rename file. You destroy namespace (package) and code will no longer work, because inside classes, this package is used. Plus there is no need to have import in the code, since you can call directly com.package-name.class from the executive code. By renaming package, you will destroy this and program will crash. It may run for a while, but once the program reach to this call, it will crash.
So this
import com.codehelper...
is not mandatory in the code, even if the code is using the package. You can write directly
com.codehelper.*** xy = new com.codehelper.***();
Even if you rename everything in the code, you still dont have guaranted functionality. Code may be using reflection and create class instances from sting code. For example see this:
Java how to instantiate a class from string
Under the line comment:
Doing some decompile -> compile work, is seems like code stealing, if you are not willing to pay licence and you want to hide it.
Plus doing something like this, it is ALWAYS a bad practice. I dont see any real use for this.
I want to add some log.debug statements to a class I'm working on, and I'd like to see that in output when running the test. I'd like to override the log4j properties on the command line, with something like this:
-Dlog4j.logger.com.mypackage.Thingie=DEBUG
I do this kind of thing frequently. I am specifically only interested in a way to pass this on the command line. I know how to do it with a config file, and that doesn't suit my workflow.
As part of your jvm arguments you can set -Dlog4j.configuration=file:"<FILE_PATH>". Where FILE_PATH is the path of your log4j.properties file.
Please note that as of log4j2, the new system variable to use is log4j.configurationFile and you put in the actual path to the file (i.e. without the file: prefix) and it will automatically load the factory based on the extension of the configuration file:
-Dlog4j.configurationFile=/path/to/log4jconfig.{ext}
These answers actually dissuaded me from trying the simplest possible thing! Simply specify a threshold for an appender (say, "console") in your log4j.configuration like so:
log4j.appender.console.threshold=${my.logging.threshold}
Then, on the command line, include the system property -Dlog4j.info -Dmy.logging.threshold=INFO. I assume that any other property can be parameterized in this way, but this is the easiest way to raise or lower the logging level globally.
With Log4j2, this can be achieved using the following utility method added to your code.
private static void setLogLevel() {
if (Boolean.getBoolean("log4j.debug")) {
Configurator.setLevel(System.getProperty("log4j.logger"), Level.DEBUG);
}
}
You need these imports
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.core.config.Configurator;
Now invoke the setLogLevel method in your main() or whereever appropriate and pass command line params -Dlog4j.logger=com.mypackage.Thingie and -Dlog4j.debug=true.
log4j does not support this directly.
As you do not want a configuration file, you most likely use programmatic configuration. I would suggest that you look into scanning all the system properties, and explicitly program what you want based on this.
Based on Thorbjørn Ravn Andersens suggestion I wrote some code that makes this work
Add the following early in the main method and it is now possible to set the log level from the comand line. This have been tested in a project of mine but I'm new to log4j and might have made some mistake. If so please correct me.
Logger.getRootLogger().setLevel(Level.WARN);
HashMap<String,Level> logLevels=new HashMap<String,Level>();
logLevels.put("ALL",Level.ALL);
logLevels.put("TRACE",Level.TRACE);
logLevels.put("DEBUG",Level.DEBUG);
logLevels.put("INFO",Level.INFO);
logLevels.put("WARN",Level.WARN);
logLevels.put("ERROR",Level.ERROR);
logLevels.put("FATAL",Level.FATAL);
logLevels.put("OFF",Level.OFF);
for(String name:System.getProperties().stringPropertyNames()){
String logger="log4j.logger.";
if(name.startsWith(logger)){
String loggerName=name.substring(logger.length());
String loggerValue=System.getProperty(name);
if(logLevels.containsKey(loggerValue))
Logger.getLogger(loggerName).setLevel(logLevels.get(loggerValue));
else
Logger.getRootLogger().warn("unknown log4j logg level on comand line: "+loggerValue);
}
}
In my pretty standard setup I've been seeing the following work well when passed in as VM Option (commandline before class in Java, or VM Option in an IDE):
-Droot.log.level=TRACE
Based on #lijat, here is a simplified implementation. In my spring-based application I simply load this as a bean.
public static void configureLog4jFromSystemProperties()
{
final String LOGGER_PREFIX = "log4j.logger.";
for(String propertyName : System.getProperties().stringPropertyNames())
{
if (propertyName.startsWith(LOGGER_PREFIX)) {
String loggerName = propertyName.substring(LOGGER_PREFIX.length());
String levelName = System.getProperty(propertyName, "");
Level level = Level.toLevel(levelName); // defaults to DEBUG
if (!"".equals(levelName) && !levelName.toUpperCase().equals(level.toString())) {
logger.error("Skipping unrecognized log4j log level " + levelName + ": -D" + propertyName + "=" + levelName);
continue;
}
logger.info("Setting " + loggerName + " => " + level.toString());
Logger.getLogger(loggerName).setLevel(level);
}
}
}
Is there a way to convert JAR lib into JAR standalone?
I need to find a standalone java executable that convert PDF into TIFF and I've found these JARs: http://www.icefaces.org/JForum/posts/list/17504.page
Any ideas?
Easiest might be to create another Jar with a Main() entry point, and then just use the java.exe executable to run it:
e.g.
> java.exe -cp MyJarMain.jar;MyPDFJar.jar com.mydomain.MyMain myPDF.pdf
Where MyMain is a class with a Main static method.
You'll need something with a main entry point to pass in and interpret some command line arguments (myPDF.pdf in my made-up example)
You could do an assembly (are you using maven?) and make sure the Main-Class entry in the manifest.mf points to the main class.
Since there is no main-Method, you have to write one, or write a whole new class to call the class/method TiffConver.convertPDF .
The question is, how you're going to use it. From the command line, you need no executable jar. From the Gui, maybe you want to pass a file to be converted by drag and drop? Then you should take the parameter(s) passed to main as Input-PDF-Names (if they end in .pdf) and pass the names iteratively to TiffConverter, for "a.pdf b.pdf" =>
TiffConver.convertPDF ("a.pdf", "a.tiff");
TiffConver.convertPDF ("b.pdf", "b.tiff");
TiffCoverter will silently overwrite existing tiffs, so check that before or change the code there - this is clearly bad habit, and look out for more such things - I didn't.
/*
* Remove target file if exists
*/
File f = new File(tif);
if (f.exists()) {
f.delete();
}
Maybe you wan't to write a swing-wrapper, which let's you choose Files interactively to be converted. This would be a nice idee, if no filename is given.
If the user passes "a.pdf xy.tiff" you could rename the converted file to xy, as additional feature.
Without a main-class, however, a standalone jar would be magic.
However, building a native executale is almost always a bad idea. You loose portability, you don't profit from security- and performance improvements to the JVM or fixed bugs. For multiple programs you need always an independend bugfix, which you might have to manage yourself, if you don't have a package-management as most linux distros have.
after clearing some questions:
public static void main (String [] args) {
if (args.length == 1 && args[0].endsWith (".pdf")) {
String target = args[0].replaceAll (".pdf$", ".tif");
convertPDF (args[0], target);
}
}
This method you put into TiffConvert. It will allow you to convert a simple pdf-File, and generate a tif-File with the same basename but ending in .tif, silently overwriting an existing one of the same name.
I guess you now need to know how to start it?
java -classpath ../classes;../jar;. parserTester
How can i get the functionality in the above command programmatically? Like, is it possible to run as:
java parserTester
and get the same result? I tried using URLClassLoader but it modifies the classpath and does not add to it.
Thanx!
Thanks for the response Milhous. But that is what i am trying to do.. How is it possible to get the jar into the classpath first? I tried using a custom classloader too :(
That works.. But sorry that i need to run it only as:
java parserTester
I would like to know if such a thing is possible???
It needs to be so bcoz i have parserTester.java and .class in a separate folder. I need to retain the file structure. The parserTester makes use of a jar in a separate jar folder.
You can use a java.net.URLClassLoader to load classes with any program defined list of URL's you wish:
public class URLClassLoader
extends SecureClassLoader
This class loader is used to load
classes and resources from a search
path of URLs referring to both JAR
files and directories. Any URL that
ends with a '/' is assumed to refer to
a directory. Otherwise, the URL is
assumed to refer to a JAR file which
will be opened as needed.
The AccessControlContext of the thread
that created the instance of
URLClassLoader will be used when
subsequently loading classes and
resources.
The classes that are loaded are by
default granted permission only to
access the URLs specified when the
URLClassLoader was created.
Since:
1.2
And a little fancy footwork can extend it to support using wildcarded pathnames to pick up entire directories of JARs (this code has some references to utility methods, but their implementation should be obvious in the context):
/**
* Add classPath to this loader's classpath.
* <p>
* The classpath may contain elements that include a generic file base name. A generic basename
* is a filename without the extension that may begin and/or end with an asterisk. Use of the
* asterisk denotes a partial match. Any files with an extension of ".jar" whose base name match
* the specified basename will be added to this class loaders classpath. The case of the filename is ignored.
* For example "/somedir/*abc" means all files in somedir that end with "abc.jar", "/somedir/abc*"
* means all files that start with "abc" and end with ".jar", and "/somedir/*abc*" means all files
* that contain "abc" and end with ".jar".
*
*/
public void addClassPath(String cp) {
String seps=File.pathSeparator; // separators
if(!File.pathSeparator.equals(";")) { seps+=";"; } // want to accept both system separator and ';'
for(StringTokenizer st=new StringTokenizer(cp,seps,false); st.hasMoreTokens(); ) {
String pe=st.nextToken();
File fe;
String bn=null;
if(pe.length()==0) { continue; }
fe=new File(pe);
if(fe.getName().indexOf('*')!=-1) {
bn=fe.getName();
fe=fe.getParentFile();
}
if(!fe.isAbsolute() && pe.charAt(0)!='/' && pe.charAt(0)!='\\') { fe=new File(rootPath,fe.getPath()); }
try { fe=fe.getCanonicalFile(); }
catch(IOException thr) {
log.diagln("Skipping non-existent classpath element '"+fe+"' ("+thr+").");
continue;
}
if(!GenUtil.isBlank(bn)) {
fe=new File(fe,bn);
}
if(classPathElements.contains(fe.getPath())) {
log.diagln("Skipping duplicate classpath element '"+fe+"'.");
continue;
}
else {
classPathElements.add(fe.getPath());
}
if(!GenUtil.isBlank(bn)) {
addJars(fe.getParentFile(),bn);
}
else if(!fe.exists()) { // s/never be due getCanonicalFile() above
log.diagln("Could not find classpath element '"+fe+"'");
}
else if(fe.isDirectory()) {
addURL(createUrl(fe));
}
else if(fe.getName().toLowerCase().endsWith(".zip") || fe.getName().toLowerCase().endsWith(".jar")) {
addURL(createUrl(fe));
}
else {
log.diagln("ClassPath element '"+fe+"' is not an existing directory and is not a file ending with '.zip' or '.jar'");
}
}
log.diagln("Class loader is using classpath: \""+classPath+"\".");
}
/**
* Adds a set of JAR files using a generic base name to this loader's classpath. See #link:addClassPath(String) for
* details of the generic base name.
*/
public void addJars(File dir, String nam) {
String[] jars; // matching jar files
if(nam.endsWith(".jar")) { nam=nam.substring(0,(nam.length()-4)); }
if(!dir.exists()) {
log.diagln("Could not find directory for Class Path element '"+dir+File.separator+nam+".jar'");
return;
}
if(!dir.canRead()) {
log.error("Could not read directory for Class Path element '"+dir+File.separator+nam+".jar'");
return;
}
FileSelector fs=new FileSelector(true).add("BaseName","EG",nam,true).add("Name","EW",".jar",true);
if((jars=dir.list(fs))==null) {
log.error("Error accessing directory for Class Path element '"+dir+File.separator+nam+".jar'");
}
else if(jars.length==0) {
log.diagln("No JAR files match specification '"+new File(dir,nam)+".jar'");
}
else {
log.diagln("Adding files matching specification '"+dir+File.separator+nam+".jar'");
Arrays.sort(jars,String.CASE_INSENSITIVE_ORDER);
for(int xa=0; xa<jars.length; xa++) { addURL(createUrl(new File(dir,jars[xa]))); }
}
}
private URL createUrl(File fe) {
try {
URL url=fe.toURI().toURL();
log.diagln("Added URL: '"+url.toString()+"'");
if(classPath.length()>0) { classPath+=File.pathSeparator; }
this.classPath+=fe.getPath();
return url;
}
catch(MalformedURLException thr) {
log.diagln("Classpath element '"+fe+"' could not be used to create a valid file system URL");
return null;
}
}
I have to agree with the other two posters, it sounds like you're overcomplicating a test class.
It's not that unusual to have the .java and .class files in separate folders, while depending on jar files in yet a third, without programmatically changing the classpath.
If you're doing it because you don't want to have to type the classpath on the command line everytime, I would suggest a shell script or batch file. Better yet, an IDE.
The question I really have is why are you doing trying to manage the classpath in code?
You could implement your own class loader, but that class/jar has to be in the classpath for it to be executed.
try
java -cp *.jar:. myClass
or
export CLASSPATH=./lib/tool.jar:.
java myClass
or
java -jar file.jar
You can write a batch file or shell script file to export the classpath and run the java program.
In Windows,
set classpath=%classpath%;../classes;../jars/*
java ParserTester
In Unix,
export classpath=%classpath%:../classes:../jars/*
java ParserTester
If you name the file name as parser.bat or parser.sh, you can just run that by calling parser in respective OS.
From java 1.6, you can include all the jars in a directory into the classpath just by saying /*
If you are trying to generate a java file dynamically, compile and add into the classpath, set the directory into which the class file gets generated in the classpath beforehand. It should load the class.
If you are modifying the already generated java class, basically recompiling after modification and if you want to load the new class, you need to use your custom class loader to avoid the caching of the class.
I think what you want is an "Execution Wrapper" or a platform specific "Launcher"... typically this component is used to detect your OS and architecture and dependencies and then makes adjustments before launching your application. It is an old school design pattern (talking 80's and earlier) but is still used a lot today. The idea is that you program can be system and environment agnostic and the launcher will make preparations and tell the software everything it needs to know. Many modern open source programs do this with Shell scripts and Batch Files, etc... Apache Tomcat for example. You could just as easily make the wrapper in java an have it launch the software with a command line exec (be sure to add " &" to the end of you exec command in *NIX so your wrapper can exit leaving only your software running... also lets you close the shell window without killing the process)
Did I understand right?! The only reason you have it that you want to launch your class without specifying the classpath and load it at runtime? ...
java parserTester
instead of
java -classpath ../classes;../jar;. parserTester
Probably I didn't get your reason. But if "that's" what you want you can do the following ( although it does not make much sense to me )
Launch the class
From the main method lauch another class an programatically set the classpath there.
End of history.
Something like the following "java -pseudo code "
public static void main( String [] args ) {
String classpath = "classes;../jar";
Runtime.getRuntime().execute("java + classpath + " parserTester ");
}
Please tell me if I get it right. If you want to do something else I would gladly help.
Excellent good post, in my case I did this to work well (note: Windows specific):
set classpath=%classpath%;../lib/*
java -cp %classpath% com.test.MyClass