Skip to content

Commit

Permalink
Add more options for parameter injection (#38)
Browse files Browse the repository at this point in the history
* feat: Add much more options for providing parameters
* test: Refactor and add tests
* feat: Split Params into multi injection and map injection
* test: Update tests
* fix: Remove debug prints
* fix: Incorrect notnull order
* feat: Make error more precise
* feat: Remove default value option from Params.java
* feat: Remove unneeded access check
* fix: Rename variable
* cleanup: Remove unused imports
* docs: Describe new behavior in readme
* docs: Add special cases
* docs: Add comment to isMapWithTypes methods
* feat: Use different (un)wrapping method
* feat: Clear map before putting values when final
  • Loading branch information
LeStegii authored Feb 16, 2024
1 parent 14fa17c commit f3b7eb4
Show file tree
Hide file tree
Showing 33 changed files with 567 additions and 152 deletions.
46 changes: 35 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,25 @@ resources that are no longer needed.

### 🎫 Parameters

To pass arguments to a controller, you can provide an additional argument to the show method, consisting of a map of
Strings and Objects. The Strings specify the argument's name and the Objects are the value of the argument. For example,
`show("/route/to/controller", Map.of("key", value))` will pass the value `value` to the argument `key`.
To pass parameters to a controller, you can provide an additional argument to the show method, consisting of a map of
strings and objects. The strings specify the argument's name and the objects are the value of the argument. For example,
`show("/route/to/controller", Map.of("key", value, "key2", value2))` will pass the value `value` to the argument `key`.

To use a passed argument in a field or method, you have to annotate it with `@Param("key")`. The name of the parameter
will be used to match it to the map of parameters passed to the `show()` method.
will be used to match it to the map of parameters passed to the `show()` method. If the annotation is used on a field,
the field will be injected with the value of the parameter before the controller is initialized. If the annotation is used
on a method, the method will be called with the value of the parameter before the controller is initialized. If the
annotation is used on a method parameter of a render/init method, the method will be called with the value of the parameter.

If `@Param` is used on a field containing a `WriteableValue` (e.g. a `StringProperty`), the value will be set to the parameter.

Instead of accessing the parameters one by one, you can also use the `@ParamsMap` annotation to inject a map of all parameters.
This annotation can be used for fields and method parameters of type `Map<String, Object>`. If the annotated field is final,
`clear` and `putAll` will be called instead.

If you want to call a setter method with multiple parameters, you can use the `@Params` annotation to specify the names of
the parameters that should be passed to the method. This annotation can be used for methods with multiple parameters.
The order of the parameters in the method has to match the order of the names in the annotation.

In order to pass arguments to the following controller, the method `show("/route/to/controller", Map.of("fofo", myFoo, "baba", myBa))`
would have to be called.
Expand All @@ -116,22 +129,28 @@ would have to be called.

@Controller
public class FooController {

private Foo foo;

// The parameter 'baba' will be injected into this field before the controller is initialized
@Param("baba")
private Bar bar;

// This field will be injected with a map of all parameters before the controller is initialized
@ParamsMap
private Map<String, Object> params;

// Default constructor (for dependency injection etc.)
@Inject
public FooController() {
}

@Params({"fofo", "baba"}) // This also works with @Param and @ParamsMap
public void setFoo(Foo foo, Bar bar) {
// This method will be called with the parameter 'fofo' and 'baba' before the controller is initialized
}

@onRender
public void render(@Param("fofo") Foo foo) {
// The parameter 'fofo' will be passed to this method upon rendering
this.bar = foo;
public void render(@Param("fofo") Foo foo, @ParamsMap Map<String, Object> params) {
// This method will be called with the parameter 'fofo' and a map of all parameters upon rendering
}

}
Expand All @@ -144,8 +163,13 @@ Any arguments not expected by the controller will be ignored.
If an argument is provided, but the type doesn't match the type of the field or method parameter, an exception will be
thrown.

Instead of accessing the parameters directly, you can also use the `@Params` annotation to inject a map of all parameters.
This annotation can be used for fields and method parameters of type `Map<String, Object>`.
The order of injection is as follows:
1. Fields will be injected with `@Param` annotations and `@ParamsMap` annotations
2. Methods annotated with `@Param` will be called
3. Methods annotated with `@Params` will be called
4. Methods annotated with `@ParamsMap` will be called
5. The controller will be initialized (`@onInit`)
6. The controller will be rendered (`@onRender`)

## 💭 Components

Expand Down
16 changes: 13 additions & 3 deletions framework/src/main/java/org/fulib/fx/annotation/param/Param.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
package org.fulib.fx.annotation.param;

import org.fulib.fx.annotation.event.onInit;
import org.fulib.fx.annotation.event.onRender;
import org.fulib.fx.controller.Router;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;


/**
* Annotation used to mark controller parameters.
* Used by the {@link Router} to inject parameters into controllers.
* Fields, parameters and methods annotated with this annotation will be injected with a parameter provided when using the {@link org.fulib.fx.FulibFxApp#show(String, Map)} method.
* <p>
* If the annotation is used on a field, the field will be injected with the specified parameter's value before initializing the controller/component.
* If the field is a writable property, the value will be set using the property's setter method (e.g. {@link javafx.beans.property.SimpleStringProperty}).
* <p>
* If the annotation is used on a method, the method will be called with the specified parameter's value initializing the controller/component.
* <p>
* If the annotation is used on a method argument, the argument will be injected with the specified parameter's value (method has to be annotated with {@link onRender} or {@link onInit}).
*/
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Param {

Expand Down
18 changes: 13 additions & 5 deletions framework/src/main/java/org/fulib/fx/annotation/param/Params.java
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
package org.fulib.fx.annotation.param;

import org.fulib.fx.controller.Router;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

/**
* Annotation used to mark controller parameters in which the {@link Router} should inject the parameter map.
* Used by the {@link Router} to inject parameters into controllers.
* Methods annotated with this annotation will be called with the values of the specified parameters when using the {@link org.fulib.fx.FulibFxApp#show(String, Map)} method.
* <p>
* Order is important, the order of the parameters in the annotation has to match the order of the parameters in the method.
*/
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Params {

/**
* The names of the parameter which should be injected.
*
* @return The name of the parameter.
*/
String[] value();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.fulib.fx.annotation.param;

import org.fulib.fx.annotation.event.onInit;
import org.fulib.fx.annotation.event.onRender;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;

/**
* Fields, parameters and methods annotated with this annotation will be injected with a map of all parameters when using the {@link org.fulib.fx.FulibFxApp#show(String, Map)} method.
* <p>
* If the annotation is used on a field, the field will be injected with the parameter map.
* <p>
* If the annotation is used on a method, the method will be called with the parameter map as an argument.
* <p>
* If the annotation is used on a method argument, the argument will be injected with the parameter map (method has to be annotated with {@link onRender} or {@link onInit}).
*/
@Target({ElementType.PARAMETER, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ParamsMap {

}
Loading

0 comments on commit f3b7eb4

Please sign in to comment.