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
14 changes: 13 additions & 1 deletion core/src/main/java/lucee/transformer/dynamic/meta/Clazz.java
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,20 @@ public static String getPackagePrefix() {
}

public static Constructor getConstructor(Class clazz, Constructor[] constructors, Object[] args, boolean convertArgument, boolean convertComparsion, Constructor defaultValue) {
// like
Class[] parameterTypes;

// LDEV-5519: exact match - parameter type must equal argument type exactly
outer: for (Constructor fm: constructors) {
if ((args.length == fm.getArgumentCount()) && clazz.getName().equals(fm.getDeclaringClassName())) {
parameterTypes = fm.getArgumentClasses();
for (int y = 0; y < parameterTypes.length; y++) {
if (args[y] == null || Reflector.toReferenceClass(parameterTypes[y]) != args[y].getClass()) continue outer;
}
return fm;
}
}

// like (assignable) - fallback if no exact match
outer: for (Constructor fm: constructors) {
if ((args.length == fm.getArgumentCount()) && clazz.getName().equals(fm.getDeclaringClassName())) {
parameterTypes = fm.getArgumentClasses();
Expand Down
60 changes: 60 additions & 0 deletions test/tickets/LDEV5519.cfc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
component extends="org.lucee.cfml.test.LuceeTestCase" {

function run( testResults, testBox ) {
describe( title='LDEV-5519 wrong constructor called - exact match should win over assignable', body=function() {

it( title='JSONObject constructor with String should parse JSON, not treat as bean', body=function() {
var jsonString = '{"name":"test"}';
var helper = new component javasettings='{
"maven": ["org.json:json:20240303"]
}' {
import org.json.JSONObject;
function parse( jsonString ) {
var jsonObj = new JSONObject( javacast( "String", jsonString.toString() ) );
return jsonObj.getString( "name" );
}
};
expect( helper.parse( jsonString ) ).toBe( "test" );
});

it( title='StringBuilder constructor with String vs CharSequence', body=function() {
// StringBuilder has StringBuilder(String) and StringBuilder(CharSequence)
// String should match StringBuilder(String) exactly
var sb = createObject( "java", "java.lang.StringBuilder" ).init( "hello" );
expect( sb.toString() ).toBe( "hello" );
});

it( title='BigDecimal constructor with String vs Object', body=function() {
// BigDecimal(String) should be called, not some other constructor
var bd = createObject( "java", "java.math.BigDecimal" ).init( "123.45" );
expect( bd.toString() ).toBe( "123.45" );
});

it( title='HashMap constructor with Map argument', body=function() {
// HashMap(Map) should work when passing a LinkedHashMap
var source = createObject( "java", "java.util.LinkedHashMap" ).init();
source.put( "key", "value" );
var copy = createObject( "java", "java.util.HashMap" ).init( source );
expect( copy.get( "key" ) ).toBe( "value" );
});

it( title='ArrayList constructor with Collection argument', body=function() {
// ArrayList(Collection) should work when passing a LinkedList
var source = createObject( "java", "java.util.LinkedList" ).init();
source.add( "item1" );
source.add( "item2" );
var copy = createObject( "java", "java.util.ArrayList" ).init( source );
expect( copy.size() ).toBe( 2 );
expect( copy.get( 0 ) ).toBe( "item1" );
});

it( title='Integer constructor with String', body=function() {
// Integer(String) should parse the string
var i = createObject( "java", "java.lang.Integer" ).init( "42" );
expect( i.intValue() ).toBe( 42 );
});

});
}

}