0

I have a method that compares the value of objects (as string, date, number...) and returns true or false depending of the result.

I've created a unit test for this method, but I'm having a problem testing the clob comparison, because with JUnit I don't have a connection, and if I use SerialClob to create two clobs (with the same content), I get objects with the same reference (so the part that compare clobs is not tested), I don't understand why two "new" generate the same object reference?

And another thing I don't understand, if I compare a string with a clob (identical values), the code that compares the clob is used, whereas instanceof is not supposed to be identical...!

What I expect is: when I compare 2 differents clobs, comparison as objects is false, as string (toString output) is false, it detects that objects are instanceof clobs, so convert them as string, and then compare string values.

Here is my code (simplified for example):

import java.io.*;
import java.sql.*;
import javax.sql.rowset.serial.*;

public class TestClob {
    
    public static void main(String[] args) throws SerialException, SQLException {
        boolean result;
        Object text1="abcdef", text2="abcdef";
        Clob clob1 = new SerialClob(((String) text1).toCharArray());
        Clob clob2 = new SerialClob(((String) text2).toCharArray());
        Clob clob3 = new SerialClob("abcdefg".toCharArray());

        System.out.println("TEST 1, basic string comparison");
        System.out.println("-------------------------------");
        result = haveSameValue(text1, text2);
        System.out.println("result: "+result);
        
        System.out.println("\nTEST 2, clob vs string");
        System.out.println("----------------------");
        result = haveSameValue(clob1, text1);
        System.out.println("result: "+result);
        
        System.out.println("\nTEST 3, different clobs objects but same value");
        System.out.println("----------------------------------------------");
        result = haveSameValue(clob1, clob2);
        System.out.println("result: "+result);
        
        System.out.println("\nTEST 4, different clobs");
        System.out.println("-----------------------");
        result = haveSameValue(clob1, clob3);
        System.out.println("result: "+result);
    } 
    
    public static boolean haveSameValue(Object obj1, Object obj2) {
        String sObj1, sObj2, sObj1Class, sObj2Class;
        boolean result = false;

        if (obj1!=null && obj2!=null) {
            sObj1Class = obj1.getClass().toString().toLowerCase();
            sObj2Class = obj2.getClass().toString().toLowerCase();
            System.out.println("  Objects class : sObj1Class="+sObj1Class+", sObj2Class="+sObj2Class);

            System.out.println("  OBJECT : obj1="+obj1+", obj2="+obj2+", => equal as object? "+obj1.equals(obj2));
            
            if (!obj1.equals(obj2)) {
                sObj1=obj1.toString();
                sObj2=obj2.toString();
                System.out.println("  STRING : sObj1="+sObj1+", sObj2="+sObj2+", => equal as string? "+sObj1.equals(sObj2));
                
                if (!sObj1.equals(sObj2)) {                 
                    if (obj1 instanceof java.sql.Clob || obj2 instanceof java.sql.Clob) {
                        sObj1 = ClobToString(obj1);
                        sObj2 = ClobToString(obj2);
                        System.out.println("  CLOB : sObj1="+sObj1+", sObj2="+sObj2+" => equal as clob? "+sObj1.equals(sObj2));
                        result = sObj1.equals(sObj2);
                    }
                    
                    // other comparisons (as a date, timestamp, number...)
                }
            }
        }
        
        return result;
    }
    
    public static String ClobToString(Object object) {
        if (object==null) {
            return null;
        }
        else if (object instanceof java.sql.Clob) {
            StringBuilder sb = new StringBuilder();
            try {
                Reader reader = ((java.sql.Clob) object).getCharacterStream();
                BufferedReader br = new BufferedReader(reader);

                String line;
                while(null != (line = br.readLine())) {
                    sb.append(line);
                }
                br.close();
                return sb.toString();
            }
            catch (Exception e) {
                System.out.println("error : "+e.getMessage());
                return object.toString();
            }
        }
        else {
            return object.toString();
        }
    }
}

and here is the output:

TEST 1, basic string comparison
-------------------------------
  Objects class : sObj1Class=class java.lang.string, sObj2Class=class java.lang.string
  OBJECT : obj1=abcdef, obj2=abcdef, => equal as object? true
result: true

TEST 2, clob vs string
----------------------
  Objects class : sObj1Class=class javax.sql.rowset.serial.serialclob, sObj2Class=class java.lang.string
  OBJECT : obj1=javax.sql.rowset.serial.SerialClob@df59efc3, obj2=abcdef, => equal as object? false
  STRING : sObj1=javax.sql.rowset.serial.SerialClob@df59efc3, sObj2=abcdef, => equal as string? false
  CLOB : sObj1=abcdef, sObj2=abcdef => equal as clob? true
result: true

TEST 3, different clobs objects but same value
----------------------------------------------
  Objects class : sObj1Class=class javax.sql.rowset.serial.serialclob, sObj2Class=class javax.sql.rowset.serial.serialclob
  OBJECT : obj1=javax.sql.rowset.serial.SerialClob@df59efc3, obj2=javax.sql.rowset.serial.SerialClob@df59efc3, => equal as object? true
result: true

TEST 4, different clobs
-----------------------
  Objects class : sObj1Class=class javax.sql.rowset.serial.serialclob, sObj2Class=class javax.sql.rowset.serial.serialclob
  OBJECT : obj1=javax.sql.rowset.serial.SerialClob@df59efc3, obj2=javax.sql.rowset.serial.SerialClob@bd7d1c2, => equal as object? false
  STRING : sObj1=javax.sql.rowset.serial.SerialClob@df59efc3, sObj2=javax.sql.rowset.serial.SerialClob@bd7d1c2, => equal as string? false
  CLOB : sObj1=abcdef, sObj2=abcdefg => equal as clob? false
result: false
8
  • 1
    "I get objects with the same reference" why do you think that?
    – talex
    Commented Oct 31, 2024 at 10:30
  • Side note: Your variable boolean result = true; should start with false as the "default" result of comparing objects. As of now, based on your current code, calling the method haveSameValue(null, "abc"); will return true saying that they have the same value (but one argument is null).
    – Progman
    Commented Oct 31, 2024 at 10:37
  • Please edit your question to include the output you are expecting (and mark the difference from the output your are currently getting).
    – Progman
    Commented Oct 31, 2024 at 10:40
  • "same reference" => see in logs for test 3, i use 2 clobs, created each of them with "new SerialClob", but in log, I see obj1=javax.sql.rowset.serial.SerialClob@df59efc3, same ending for obj2. @Progman: you're right, it's better with false, it is just an example here, not my complete code. And what I expect for my unit test is, when I compare a clob1 to clob2 (with same value), that : when compare as objects, they are differents, when compare toString output, they are different, it detects they are clobs, so convert them to string, and compare them as string
    – vinsse2001
    Commented Oct 31, 2024 at 10:53
  • 2
    See Object.toString(). The part after @ is the hashcode (in hex) by default, and has nothing to do with the reference. It is required to be the same for equal objects.
    – Hulk
    Commented Oct 31, 2024 at 13:09

1 Answer 1

2

The variables clob1 and clob2 are referencing different objects, since new objects are created with the new keyword. However, these objects have the same "value" in them. The SerialClob.equals() method is defined in such a way, that two SerialClob instances are equal to each other, when they have the same value:

Compares this SerialClob to the specified object. The result is true if and only if the argument is not null and is a SerialClob object that represents the same sequence of characters as this object.

This is the case here, they have the same value "abcdef" in them. This means that the if block

if (!obj1.equals(obj2)) {
    ...
}

is not entered. And therefore, no further check is executed since you already know they are "equal".

3
  • ok, thanks for this precision with SerialClob object, but when I test with real values (2 javq.sql.clobs with identical values, extracted from oracle database), debug shows that object.equals is false, toString values are also differents, so comparison go through "if clob part", convert them into string and comparison return true at this point. How can I create a junit test on this, because I can't instantiate java.sql.Clob without connection? The only way I found, to go through this part with junit, is to compare a clob with a string...
    – vinsse2001
    Commented Oct 31, 2024 at 13:23
  • 1
    @vinsse2001 java.sql.Clob is only an interface. Depending on what you want to do/test, you can create a dummy implementation of that interface in your unit test and run your code with instances of them.
    – Progman
    Commented Oct 31, 2024 at 13:46
  • good idea, i will try it, thanks!
    – vinsse2001
    Commented Oct 31, 2024 at 15:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.