jpype icon indicating copy to clipboard operation
jpype copied to clipboard

java.lang.String is not java.lang.String

Open pulkin opened this issue 1 month ago • 3 comments

Thanks for the great project!

Somehow in pytests I can end up with this error:

        from java.lang import String                                 
>       assert type(a) is String, f"not a string: {type(a)}"
E       AssertionError: not a string: <java class 'java.lang.String'>

It happens in a multiprocessing-heavy context. Otherwise I did not investigate much into it (need to run a very large test suite to reproduce). Worth noting that it is probably not related to serializing the object because it would otherwise simply fail during serialization.

jpype 1.6.0 cpython 3.9.18

pulkin avatar Nov 17 '25 13:11 pulkin

Unfortunately while Java strings and Python string seem compatible they sadly are not. Use ‘str(x)’ on a Java string if you want a Python one.

Thrameos avatar Nov 17 '25 18:11 Thrameos

The funny thing is, it is a part of the function that converts String to str

def jstr(a: Any) -> str:
    from java.lang import String
    assert type(a) is String, f"not a string: {type(a)}"
    return str(a)

I used it for debugging purposes mostly to ensure that I do not convert something non-String to str. Ended up with this one

def jstr(a: Any) -> str:
    assert str(type(a)) == "<java class 'java.lang.String'>", f"not a string: {type(a)}"
    return str(a)

Not a big deal for sure: just wondering what happens here.

pulkin avatar Nov 18 '25 10:11 pulkin

I am guessing that you are hit by the fact that back end has multiple String instances and you are checking “is”. Likely you meant isinstance(a, JString) which would be safer as then you would have caught the internal subtyping properly.

import jpype jpype.startJVM() j =jpype.JString("a") j.class.mro (<java class 'java.lang.String'>, <java class 'java.io.Serializable'>, <java class 'java.lang.Comparable'>, <java class '_jpype._JComparable'>, <java class 'java.lang.CharSequence'>, <java class 'java.lang.constant.Constable'>, <java class 'java.lang.constant.ConstantDesc'>, <java class 'java.lang.Object'>, <java class '_jpype._JObject'>, <class 'object'>) jpype.JString.mro (<java class 'JString'>, <java class '_jpype._JObject'>, <class 'object'>)

isinstance(j, jpype.JString) True isinstance(j, jpype.java.lang.String) True

As you can see string is a complex set of wrappers not a simple type. So “is” won’t work. Depending on whether you are passing a String created in Java or something that Python can cast to a String will give different type trees. And during startup some String instances must be created before the formal string is declared adding to the confusion as to which wrapper type you may have.

Thrameos avatar Nov 18 '25 17:11 Thrameos