1

I have a requirement in which Java method name needs to be added in logger in the first line of the method.

I am trying the following approach.

  1. Get lines with keyword private, protected or public and the character (. This will identify the method definition.
  2. Extract the method name
  3. When method name is found, add a new line after 2 lines, and add
    Logger.add(Constants.METHOD_name, "name of the method")
    
    where "name of the method" is one extracted in step 2.

I have tried the below code.

#! /bin/bash

arr=($(grep -E 'public|private|protected' DataServiceImpl.java | grep "(" | awk '{print$3}' | awk -F'(' '{print $1}'))

for (( i=0; i<${#arr[@]}; ++i )); do
   sed "/${arr[$i]}(/{N;a Logger.add(Constants.METHOD_NAME,\"${arr[$i]}\");
   }" DataServiceImpl.java > changedText.txt && mv changedText.txt DataServiceImpl.java
done

It works fine. But the problem is it inserts the new line and Logger.add after the calling line also.

For instance, if I have a method public String getProtocol(), it adds the line

Logger.add(Constants.METHOD_NAME,"getProtocol")

as first line of the method definition. It also adds it in the place where getProtocol() is called.

How can this be avoided? Is there a way we can do something like this?

#! /bin/bash

arr=($(grep -E 'public|private|protected' DataServiceImpl.java | grep "("))

for (( i=0; i<${#arr[@]}; ++i )); do

//search for match of array element. This would result in complete line till (
//If match found, add a line after two lines and add the below code.
//Extract 3rd column of array element. In public String getProtocol, we will get getProtocol
//Logger.add(Constants.METHOD_NAME, "extracted column")
done

Sample Java Class:

public class DataServiceImpl
   {
     public String getProtocol()
     {
        return "https";
     }
     public String buildUrl()
     {
       String url = getProtocol()+"://www.google.com";
       return url;
     }
}

Expected Result:

public class DataServiceImpl
   {
     public String getProtocol()
     {
        Logger.add(Constants.METHOD_NAME,"getProtocol");
        return "https";
     }
     public String buildUrl()
     {
       Logger.add(Constants.METHOD_NAME,"buildUrl");
       String url = getProtocol()+"://www.google.com";
       return url;
     }
}

Also it would be helpful if there is a way to specify that the line Logger.add should be added below { and one space after the alignment of {. Thanks.

3
  • Please edit your question and add an example of your input file that we can use to test our solutions. Also show the output you would expect from that example.
    – terdon
    May 25 '20 at 12:46
  • Edited the question with sample class and the expected result. May 25 '20 at 13:21
  • The indenting is not consistent, can you please correct it?
    – Quasímodo
    May 25 '20 at 14:03
0

We shall employ GNU sed in extended regex mode (to make the regex writing tractable, to some extent): P. S: This is not a parser so expect some corner cases to trip up sometimes.

$ sed -re '
    /^\s*(public|private|protected)\s.*[(]/!b
    h;s/\S+/\n/2;s/.*\n\s+//;s/[(].*//



  s/.*/Logger.add(Constants.METHOD_NAME,"&");/
    x;n;n;x;G
    s/.*\n(\s*).*/\1&/
' file.java

Method: Isolate the line of interest. Then get the method name and decorate it with the required logging terminology. After that skip two lines and print.

0

This is much simpler, clearer, more portable, etc, with awk, e.g. with GNU awk for the 3rd arg to match(), gensub(), and \s/\S shorthand:

$ cat tst.awk
match($0,/(private|protected|public).*\s(\S+)\s*\(/,a) {
    methodName = a[2]
    lineNr = NR+2
}
NR == lineNr {
    indent = gensub(/\S.*/,"",1)
    printf "%sLogger.add(Constants.METHOD_NAME,\"%s\");\n", indent, methodName
    lineNr = 0
}
{ print }

.

$ awk -f tst.awk file
public class DataServiceImpl
   {
     public String getProtocol()
     {
        Logger.add(Constants.METHOD_NAME,"getProtocol");
        return "https";
     }
     public String buildUrl()
     {
       Logger.add(Constants.METHOD_NAME,"buildUrl");
       String url = getProtocol()+"://www.google.com";
       return url;
     }
}

or using any awk in any shell on every UNIX box:

$ cat tst.awk
/(private|protected|public).*\(/ {
    methodName = $0
    sub(/[[:space:]]*\(.*/,"",methodName)
    sub(/.*(private|protected|public).*[[:space:]]/,"",methodName)
    lineNr = NR+2
}
NR == lineNr {
    indent = $0
    sub(/[^[:space:]].*/,"",indent)
    printf "%sLogger.add(Constants.METHOD_NAME,\"%s\");\n", indent, methodName
    lineNr = 0
}
{ print }

.

$ awk -f tst.awk file
public class DataServiceImpl
   {
     public String getProtocol()
     {
        Logger.add(Constants.METHOD_NAME,"getProtocol");
        return "https";
     }
     public String buildUrl()
     {
       Logger.add(Constants.METHOD_NAME,"buildUrl");
       String url = getProtocol()+"://www.google.com";
       return url;
     }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.