Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions core/src/main/java/lucee/runtime/reflection/Reflector.java
Original file line number Diff line number Diff line change
Expand Up @@ -953,9 +953,19 @@ public static MethodInstance getGetter(Class clazz, String prop, boolean nameCas
* @return return Value of the getter Method
*/
public static MethodInstance getGetterEL(Class clazz, String prop, boolean nameCaseSensitive) {
prop = "get" + StringUtil.ucFirst(prop);
MethodInstance mi = getMethodInstance(clazz, KeyImpl.init(prop), ArrayUtil.OBJECT_EMPTY, nameCaseSensitive, false);
if (!mi.hasMethod()) return null;
String ucFirst = StringUtil.ucFirst(prop);
MethodInstance mi = getMethodInstance(clazz, KeyImpl.init("get" + ucFirst), ArrayUtil.OBJECT_EMPTY, nameCaseSensitive, false);
if (!mi.hasMethod()) {
mi = getMethodInstance(clazz, KeyImpl.init("is" + ucFirst), ArrayUtil.OBJECT_EMPTY, nameCaseSensitive, false);
if (!mi.hasMethod()) return null;
try {
Class rtn = mi.getMethod().getReturnClass();
if (rtn != Boolean.class && rtn != boolean.class) return null;
}
catch (PageException e) {
return null;
}
}
try {
if (mi.getMethod().getReturnClass() == void.class) return null;
}
Expand Down
66 changes: 66 additions & 0 deletions test/tickets/LDEV6377.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
component extends="org.lucee.cfml.test.LuceeTestCase" labels="reflection" {

function run( testResults, testBox ) {

describe( "LDEV-6377 obj.foo resolves is*() boolean getters on Java objects", function() {

var tmpFile = createObject( "java", "java.io.File" ).init( getTempDirectory() );
var emptyStr = "";
var nonEmptyStr = "lucee";
var emptyList = createObject( "java", "java.util.ArrayList" ).init();
var fullList = createObject( "java", "java.util.ArrayList" ).init();
fullList.add( "one" );

it( title="File.isHidden() via .hidden shorthand", body=function() {
// On a directory like getTempDirectory(), isHidden is typically false on Windows
// but we only care that the property resolves at all (no "no property" exception)
expect( tmpFile.hidden ).toBe( tmpFile.isHidden() );
});

it( title="File.isDirectory() via .directory shorthand", body=function() {
expect( tmpFile.directory ).toBeTrue();
expect( tmpFile.directory ).toBe( tmpFile.isDirectory() );
});

it( title="File.isFile() via .file shorthand", body=function() {
expect( tmpFile.file ).toBeFalse();
expect( tmpFile.file ).toBe( tmpFile.isFile() );
});

it( title="File.isAbsolute() via .absolute shorthand", body=function() {
expect( tmpFile.absolute ).toBeTrue();
expect( tmpFile.absolute ).toBe( tmpFile.isAbsolute() );
});

it( title="String.isEmpty() via .empty shorthand (primitive boolean return)", body=function() {
expect( emptyStr.empty ).toBeTrue();
expect( nonEmptyStr.empty ).toBeFalse();
});

// SKIPPED: Lucee's Reflector.getProperty checks fields BEFORE the getter path.
// ArrayList has a private static EMPTY_ELEMENTDATA field that gets matched by
// getFieldsIgnoreCase (Lucee bypasses access modifiers), returning the field
// name "EMPTY" before isEmpty() is ever called. Unrelated to LDEV-6377 —
// the is*() fallback works correctly (see String.empty above); this is a
// pre-existing quirk in the field-vs-getter precedence.
xit( title="ArrayList.isEmpty() via .empty shorthand", body=function() {
expect( emptyList.empty ).toBeTrue();
expect( fullList.empty ).toBeFalse();
});

it( title="property name is case-insensitive", body=function() {
expect( tmpFile.HIDDEN ).toBe( tmpFile.isHidden() );
expect( tmpFile.Directory ).toBe( tmpFile.isDirectory() );
});

it( title="missing property still throws (negative path preserved)", body=function() {
expect( function() {
var x = tmpFile.totallyMadeUpProperty;
}).toThrow();
});

});

}

}
Loading