SagittariusA
SagittariusA

Reputation: 5427

Java: same strings got with StringBuilder are not equals in the end

Out product is integrated with Drools and user can add/edit/deletd Drools functions from/to a package by loading the entire package in a simple long scrolling JTextArea and literally directly editing some DRools functions; or, better, copy and paste the whole package after editing it with another instrument (like Notepad++). When the new package is persisted, I have to parse it with its previous version stored in a DB and audit differences in existing functions, or inserted/deleted ones. I already had a class which splits a Drools functions into its component, to which I added this method to recover a snapshot of the function to be stored:

public String getFunctionCode() {
    StringBuilder strBld = new StringBuilder("function ");

    if (this.returnType == null)
        strBld.append("void");
    else
        strBld.append(this.returnType);

    strBld.append(" ");
    strBld.append(this.name);
    strBld.append("(");

    if (this.paramNames != null && !this.paramNames.isEmpty()) {
        int parametersSize = this.paramTypes.size();
        for (int i = 0; i < parametersSize; i++) {
            strBld.append(this.paramTypes.get(i).getName());
            strBld.append(" ");
            strBld.append(this.paramNames.get(i).getName());
            if (i < parametersSize - 1)
                strBld.append(",");
        }
    }

    strBld.append(") {");

    if (this.text == null || this.text.trim().isEmpty())
        strBld.append(" ");
    else
        strBld.append(this.text);

    strBld.append("}\r\n");

    return strBld.toString();
}

where paramNames and paramTypes are simply a List<String> containing the signature of the function, while text contains the body of the function between the two main { } after the signature. It happens only sometimes that all the other functions of package are detected as edited, even if user added or deleted another one. Why this? It this because of some not printable character? If I compare the two snapshots stored on DB with a text diff tool, nothing is detected. To get changed functions, in a for loop I do:

for (FunctionInfo functionInfo : updatedFunctions) {
    FunctionInfo oldFunction = oldPackageInfo.getFunction(functionInfo.getName());

    String oldFunctionBody = oldFunction.getFunctionCode();
    String newFunctionBody = functionInfo.getFunctionCode();

    if (!newFunctionBody.equals(oldFunctionBody)) {
      /* persist an audit record */
    }
}

where updatedFunctions is a List<FunctionInfo> got by retrieving all functions in common between old persisted package and the one arriving from front end, after sorting them by name. Which could be the cause?

UPDATE I started Wildfly in debug mode and I on Eclipse a breakpoint inside the if statement in the previous loop. Than, using this online tool for text diff I compared oldFunctionBody and newFunctionBody of a function I did not edited from the frontend window. It turns out that old untouched functions coming from front end were added with some unprintable characters, overall with many \r. Why this happens?

Old function:

function void disableTestOnDevice(SampleBuilder sample,String devices,String[] devTestCode) {\r\n\t\t   if(devices == null)\r\n\t\t\t   return;\r\n\t       if(sample.getListTransc() != null && sample.getListTransc().size() > 0){\t\r\n\t\t\t\tfor(int i = sample.getListTransc().size()-1; i >= 0; i--){\r\n\t\t\t\t\tViewWorklistBuilder j = (ViewWorklistBuilder)sample.getListTransc().get(i);\r\n\t\t\t\t\tif(j.getDeviceId() == null || j.getDeviceTestCode() == null || j.getDeviceSpecimenCode() == null){\r\n\t\t\t\t\t\tcontinue;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tif(j.getDeviceId().equals(devices)){\r\n\t\t\t\t\t\tif(devTestCode != null){\r\n\t\t\t\t\t\t\tfor(int k = 0;  k < devTestCode.length; k++){\r\n\t\t\t\t\t\t\t\tif(j.getDeviceTestCode().equals(devTestCode[k])){\r\n\t\t\t\t\t\t\t\t\tj.setEnabled(0);\r\n\t\t\t\t\t\t\t\t\tbreak;\r\n\t\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\t\t\r\n\t\t\t\t}\r\n\t       }\r\n\t\r\n

New function:

function void disableTestOnDevice(SampleBuilder sample,String devices,String[] devTestCode) {\n\t\t   if(devices == null)\n\t\t\t   return;\n\t       if(sample.getListTransc() != null && sample.getListTransc().size() > 0){\t\n\t\t\t\tfor(int i = sample.getListTransc().size()-1; i >= 0; i--){\n\t\t\t\t\tViewWorklistBuilder j = (ViewWorklistBuilder)sample.getListTransc().get(i);\n\t\t\t\t\tif(j.getDeviceId() == null || j.getDeviceTestCode() == null || j.getDeviceSpecimenCode() == null){\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tif(j.getDeviceId().equals(devices)){\n\t\t\t\t\t\tif(devTestCode != null){\n\t\t\t\t\t\t\tfor(int k = 0;  k < devTestCode.length; k++){\n\t\t\t\t\t\t\t\tif(j.getDeviceTestCode().equals(devTestCode[k])){\n\t\t\t\t\t\t\t\t\tj.setEnabled(0);\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\t\t\n\t\t\t\t}\n\t       }\n\t\r\n

Upvotes: 0

Views: 325

Answers (2)

According to your last update. The main difference between the "old function" and the "new function" results are the carry return characters (I think that there is a tab character missing there, too). Anyway, to avoid this kind of issues I recommend you use System.lineSeparator(), introduced in JDK7:

Returns the system-dependent line separator string. It always returns the same value - the initial value of the system property line.separator. On UNIX systems, it returns "\n"; on Microsoft Windows systems it returns "\r\n". Reference: https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#lineSeparator()

Additionally, I recommend you use fixing space size instead of \t due to different application replace it in different ways. I mean in different tab size. So, for example a clean solution could be create a constant called TAB : " " and replace it everywhere you use \t.

final String TAB = "  ";

Finally, I notice that you are returning the value of the StringBuilder as string, then, I guess that when you are doing the comparison you have the text stored in some String variable. Which could be useful if you are initializing as UTF-8 encoding (just for say one).

Upvotes: 1

Raymo111
Raymo111

Reputation: 584

You need to rewrite the default .equals() method to specify how you think it's equal in your classes where you compare objects, if the default comparison is not working for you.

Edit: See the documentation for Java 7 and the tutorial for javase for more information. Also see this post on when to use StringBuilder.

Upvotes: 1

Related Questions