1313import java .lang .invoke .MethodHandles ;
1414import java .lang .invoke .MethodType ;
1515import java .lang .reflect .Method ;
16+ import java .lang .reflect .Parameter ;
1617import java .util .*;
1718import java .util .concurrent .ConcurrentHashMap ;
1819import java .util .regex .Matcher ;
20+ import java .util .regex .Pattern ;
1921import java .util .stream .Collectors ;
2022
2123/**
@@ -338,8 +340,8 @@ private synchronized void initializePattern(Application app, String path, Method
338340 String group = extractGroupFromPath (path );
339341
340342 if (method != null ) {
343+ PatternBuilder patternBuilder = buildPattern (path , method );
341344 Class <?>[] types = method .getParameterTypes ();
342- PatternBuilder patternBuilder = buildPattern (path , types );
343345
344346 try {
345347 MethodHandles .Lookup lookup = MethodHandles .lookup ();
@@ -349,7 +351,7 @@ private synchronized void initializePattern(Application app, String path, Method
349351 List <Action > actions = patternGroups .getOrDefault (group , new ArrayList <>());
350352 Action action = createAction (actions .size (), app , patternBuilder .getExpression (),
351353 handle , method .getName (), method .getReturnType (),
352- method . getParameterTypes () , patternBuilder .getPriority (), mode );
354+ types , patternBuilder .getPriority (), mode );
353355
354356 actions .add (action );
355357 patternGroups .put (group , actions );
@@ -376,37 +378,86 @@ private Action createAction(int id, Application app, String expression, MethodHa
376378 /**
377379 * Build a pattern and calculate priority for method parameters
378380 */
379- private PatternBuilder buildPattern (String path , Class <?>[] types ) {
380- String patternPrefix = "^/?" + path ;
381- StringBuilder patterns = new StringBuilder ();
381+ private PatternBuilder buildPattern (String path , Method method ) {
382382 int priority = 0 ;
383+ Parameter [] parameters = method .getParameters ();
384+ org .tinystruct .system .annotation .Action annotation = method
385+ .getAnnotation (org .tinystruct .system .annotation .Action .class );
386+
387+ // Extract "data" parameters (skipping Request/Response)
388+ List <ParameterInfo > dataParams = new ArrayList <>();
389+ int dataIndex = 0 ;
390+ for (int i = 0 ; i < parameters .length ; i ++) {
391+ Parameter parameter = parameters [i ];
392+ Class <?> type = parameter .getType ();
393+ if (!Request .class .isAssignableFrom (type ) && !Response .class .isAssignableFrom (type )) {
394+ String name = parameter .getName ();
395+ // Check if there's an @Argument annotation providing a name
396+ if (annotation != null && i < annotation .arguments ().length ) {
397+ name = annotation .arguments ()[i ].key ();
398+ }
399+ dataParams .add (new ParameterInfo (dataIndex ++, type , name ));
400+ }
401+ }
383402
384- if (types .length > 0 ) {
385- for (Class <?> type : types ) {
386- if (Request .class .isAssignableFrom (type ) || Response .class .isAssignableFrom (type ))
387- continue ;
403+ int parameterIndex = 0 ;
404+ String finalPath = path ;
405+
406+ if (path != null && !path .isEmpty ()) {
407+ Matcher m = Pattern .compile ("\\ {([^/]*)\\ }" ).matcher (path );
408+ StringBuilder sb = new StringBuilder ();
409+ int lastEnd = 0 ;
410+ while (m .find ()) {
411+ String placeholderName = m .group (1 );
412+ ParameterInfo matchedParam = null ;
413+ // Try to find a parameter by name
414+ for (ParameterInfo param : dataParams ) {
415+ if (param .name .equals (placeholderName )) {
416+ matchedParam = param ;
417+ break ;
418+ }
419+ }
388420
389- PatternPriority patternPriority = getPatternForType (type );
390- priority += patternPriority .getPriority ();
421+ // If not found by name, just take the next data parameter (fallback or
422+ // index-based)
423+ if (matchedParam == null && parameterIndex < dataParams .size ()) {
424+ matchedParam = dataParams .get (parameterIndex );
425+ }
391426
392- String pattern = "(" + patternPriority .getPattern () + ")" ;
393- if (patterns .length () != 0 ) {
394- patterns .append ("/" );
427+ if (matchedParam != null ) {
428+ sb .append (path , lastEnd , m .start ());
429+ PatternPriority patternPriority = getPatternForType (matchedParam .type );
430+ priority += patternPriority .getPriority ();
431+ sb .append ("(" ).append (patternPriority .getPattern ()).append (")" );
432+ parameterIndex ++;
433+ lastEnd = m .end ();
395434 }
396- patterns .append (pattern );
397435 }
436+ sb .append (path .substring (lastEnd ));
437+ finalPath = sb .toString ();
438+ }
398439
399- String expression ;
400- if (patterns .length () > 0 ) {
401- expression = patternPrefix + "/" + patterns + "$" ;
402- } else {
403- expression = patternPrefix + "$" ;
440+ StringBuilder expression = new StringBuilder ("^/?" ).append (finalPath );
441+
442+ // Handle remaining parameters (Legacy behavior)
443+ StringBuilder patterns = new StringBuilder ();
444+ while (parameterIndex < dataParams .size ()) {
445+ ParameterInfo param = dataParams .get (parameterIndex ++);
446+ PatternPriority patternPriority = getPatternForType (param .type );
447+ priority += patternPriority .getPriority ();
448+
449+ if (!patterns .isEmpty ()) {
450+ patterns .append ("/" );
404451 }
452+ patterns .append ("(" ).append (patternPriority .getPattern ()).append (")" );
453+ }
405454
406- return new PatternBuilder (expression , priority );
407- } else {
408- return new PatternBuilder (patternPrefix + "$" , 0 );
455+ if (!patterns .isEmpty ()) {
456+ expression .append ("/" ).append (patterns );
409457 }
458+
459+ expression .append ("$" );
460+ return new PatternBuilder (expression .toString (), priority );
410461 }
411462
412463 /**
@@ -451,6 +502,18 @@ public int getPriority() {
451502 }
452503 }
453504
505+ private static class ParameterInfo {
506+ final int index ;
507+ final Class <?> type ;
508+ final String name ;
509+
510+ ParameterInfo (int index , Class <?> type , String name ) {
511+ this .index = index ;
512+ this .type = type ;
513+ this .name = name ;
514+ }
515+ }
516+
454517 /**
455518 * Gets pattern and priority for a specific parameter type
456519 */
0 commit comments