Can i create a list using a renderer in Hybris? - spring

I have a renderer with one object(OrderEntryModel) that contains a list of objects and i want to create a list in backoffice with that objects(OrderEntryItemModel). It can be possible?
public class *Renderer implements WidgetComponentRenderer<Listcell, ListColumn, OrderEntryModel> {
#Override
public void render(final Listcell listcell, final ListColumn configuration, final OrderEntryModel orderEntryModel,
final DataType dataType, final WidgetInstanceManager widgetInstanceManager) {
}

Related

How to set a tableview in JavaFX in initialize method

Hi I'm new to JavaFX and want to populate a tableview with data
I use not the programmatic way I create the tableview with scene builder and have a controller file . I have a data file for the getters and setters already and created a observable list
public class Controller implements Initializable {
#FXML TableView<Bew> tableV;
#FXML TableColumn<Bew, String> nameCol =new TableColumn<>("Name");
#FXML TableColumn<Bew, String> dateCol =new TableColumn<>("Datum");
#FXML TableColumn<Bew, String> actionCol =new TableColumn<>("Aktivität");
#FXML TableColumn<Bew, String> infoCol =new TableColumn<>("Info");
#Override
public void initialize(URL url, ResourceBundle resourceBundle) {
SQLiteDB DB = new SQLiteDB();
ObservableList<Bew> list = DB.getData();
tableV.setItems(list);
}
public ObservableList<Bew> getData() {
ObservableList<Bew> bewList = FXCollections.observableArrayList();
bewList.add(new Bew("Rita", "01.12.1920", "Gespräch", "gud"));
bewList.add(new Bew("Marc", "14.03.1930", "Spaziergang", "gud"));
bewList.add(new Bew("Peter", "27.01.1901", "dfdsfdsfdsfdsf", "gud"));
bewList.add(new Bew("John", "12.12.1912", "dfdsfdsfdsfdsf", "gud"));
return bewList;
}
When I run the code no error appears but no data in tableview
Any help?

Custom Object as a #RequestParam

I have a paginated endpoint that looks like this /api/clients?range=0-25.
I'd like the getClients() method in my ClientController to directly receive an instance of a custom Range object rather than having to validate a "0-25" String but I'm having trouble figuring this out.
#Getter
final class Range {
#Min(0)
private Integer offset = 0;
#Min(1)
private Integer limit = 25;
}
#ResponseBody
#GetMapping(params = { "range" })
public ResponseEntity<?> getAllClients(#RequestParam(value = "range", required = false) QueryRange queryRange, final HttpServletResponse response) {
...
}
I'm not sure how to instruct the Controller to correctly deserialize the "0-25" string into the Range...
You can use a Converter<S, T>, as shown below:
#Component
public class RangeConverter implements Converter<String, Range> {
#Override
public Range convert(String source) {
String[] values = source.split("-");
return new Range(Integer.valueOf(values[0]), Integer.valueOf(values[1]));
}
}
You also could handle invalid values according to your needs. If you use the above converter as is, the attempt to convert an invalid value such as 1-x will result in a ConversionFailedException.
You can also do the following it seems :
public class QueryRangeEditor extends PropertyEditorSupport {
private static final Pattern PATTERN = Pattern.compile("^([1-9]\\d*|0)-([1-9]\\d*|0)$");
#Override
public void setAsText(String text) throws IllegalArgumentException {
final QueryRange range = new QueryRange();
Matcher matcher = PATTERN.matcher(text);
if (matcher.find()) {
range.setOffset(Integer.valueOf(matcher.group(1)));
range.setLimit(Integer.valueOf(matcher.group(2)));
} else {
throw new IllegalArgumentException("OI"); // todo - replace
}
setValue(range);
}
}
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(QueryRange.class, new QueryRangeEditor());
}
But #cassiomolin's looks cleaner...

MVC javafx Application, when to inject model

I've got an application which i try to keep the mvc rule. I've got a model
public class CarTableView {
SimpleIntegerProperty id = new SimpleIntegerProperty();
SimpleStringProperty brand = new SimpleStringProperty();
SimpleStringProperty engine = new SimpleStringProperty();
SimpleBooleanProperty navi = new SimpleBooleanProperty();
SimpleBooleanProperty available = new SimpleBooleanProperty();
SimpleDoubleProperty liters = new SimpleDoubleProperty();
SimpleIntegerProperty power = new SimpleIntegerProperty();
ObservableList<CarTableView> observableList = FXCollections.observableArrayList();
public CarTableView()
{
}
public CarTableView(int id,String brand,String engine,Boolean navi,Boolean available,double liters,int power)
{
this.id.set(id);
this.brand.set(brand);
this.engine.set(engine);
this.navi.set(navi);
this.available.set(available);
this.liters.set(liters);
this.power.set(power);
}
Which I need to use in my two controllers in order to get referance to ObservableList. And here is where lie my problem. Where to create the Model? I need him to be created before the initialize() method will invoked
public class MainController {
private CarTableView model = new CarTableView();
#FXML
private Button addVehicleButton;
#FXML
private Button showClientDatabaseButton;
#FXML
public void initialize()
{
(...)
model.getObservableList().add(new CarTableView(213,"FIAT","1.9 JTD",true,true,32.4,132)); // HERE I use model (it's fine here because its created in this class)
tableView.setItems(model.getObservableList());
#FXML
public void addNewVehicleButtonClicked() throws IOException
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/AddNewCar.fxml"));
Stage stage = new Stage();
Scene scene = new Scene((Pane)loader.load());
stage.setScene(scene);
stage.show();
AddNewCarController addNewCarController = loader.getController();
addNewCarController.initData(model); // HERE i try to initialize model in second controller
}
But I need him also in initialize() method from another controller
public class AddNewCarController {
private ObservableList<String> choiceBoxList = FXCollections.observableArrayList("YES","NO");
#FXML
public void initialize()
{
autoIncrementChekBox.setSelected(true);
if(autoIncrementChekBox.isSelected())
{
idTextField.setText(Integer.toString((model.getObservableList().size()+1))); // HERE I NEED HIM TOO!! But it is null... he havent been load yet!
idTextField.setDisable(true);
}
comboBox.setItems(choiceBoxList);
comboBox.setValue("YES");
}
In this situation even if I will pass the data throw function initModel() in second controller. Where I should have create model, and pass to both controller?
I will also add my Main() file to clear situation
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Managment System");
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
Scene scene = new Scene((Pane)loader.load(),1800,900);
MainController mainController = loader.getController();
stage.setScene(scene);
stage.show();
}
}
You can create the controller so that the model is passed to the constructor:
public class MainController {
private final CarTableView model ;
public MainController(CarTableView model) {
this.model = model ;
}
// existing code ...
}
To use this version of the controller, do
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) throws Exception {
stage.setTitle("Managment System");
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
CarTableView model = new CarTableView();
MainController mainController = new MainController(model);
loader.setController(mainController);
Scene scene = new Scene((Pane)loader.load(),1800,900);
stage.setScene(scene);
stage.show();
}
}
And remove the fx:controller attribute from the FXML file.
You can then do the same when you load the other FXML file, using the same instance of the model.
A related approach is to use a controller factory:
CarTableView model = new CarTableView() ;
Callback<Class<?>, Object> controllerFactory = controllerType -> {
if (controllerType == MainController.class) {
return new MainController(model);
} else {
throw new IllegalStateException("Unexpected controller class: "+controllerType.getName());
}
};
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Main.fxml"));
loader.setControllerFactory(controllerFactory);
Scene scene = new Scene(loader.load(), 1800, 900);
// ...
In this version, you keep the fx:controller attribute in the FXML file.
The basic idea here is that the controller factory is a function that maps the type of the controller to the controller instance, so you can use the controller factory to configure how the controller is created. You can use reflection to make this reusable (get the constructors for the class, check if any of them take a single parameter whose type is the model type, and invoke that constructor if so, otherwise just invoke the default constructor).
You can also use this technique to use a dependency injection framework such as Spring to create your controllers: see Dependency Injection and JavaFX. This, of course, means you can use Spring to inject the model into the controllers, which becomes very nice.
Finally, note that there is a JavaFX-specific dependency injection framework, afterburner.fx. This basically uses this technique under the hood to allow you to simply use javax.inject annotations directly in the controllers, so you just have to annotate the model in order to automatically inject it. If you have a medium-large scale application with lots of injection required, this is a very good option.

Spring #Value property for custom class

Is it possible to use Spring's #Value annotation to read and write property values of a custom class type?
For example:
#Component
#PropertySource("classpath:/data.properties")
public class CustomerService {
#Value("${data.isWaiting:#{false}}")
private Boolean isWaiting;
// is this possible for a custom class like Customer???
// Something behind the scenes that converts Custom object to/from property file's string value via an ObjectFactory or something like that?
#Value("${data.customer:#{null}}")
private Customer customer;
...
}
EDITED SOLUTION
Here is how I did it using Spring 4.x APIs...
Created new PropertyEditorSupport class for Customer class:
public class CustomerPropertiesEditor extends PropertyEditorSupport {
// simple mapping class to convert Customer to String and vice-versa.
private CustomerMap map;
#Override
public String getAsText()
{
Customer customer = (Customer) this.getValue();
return map.transform(customer);
}
#Override
public void setAsText(String text) throws IllegalArgumentException
{
Customer customer = map.transform(text);
super.setValue(customer);
}
}
Then in application's ApplicationConfig class:
#Bean
public CustomEditorConfigurer customEditorConfigurer() {
Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<Class<?>, Class<? extends PropertyEditor>>(1);
customEditors.put(Customer.class, CustomerPropertiesEditor.class);
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(customEditors);
return configurer;
}
Cheers,
PM
You have to create a class extending PropertyEditorSupport.
public class CustomerEditor extends PropertyEditorSupport {
#Override
public void setAsText(String text) {
Customer c = new Customer();
// Parse text and set customer fields...
setValue(c);
}
}
It's possible but reading Spring documentation. You could see this example:
Example usage
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
See details here
Spring can read properties and load them directly into a class.
Moreover, you can add #ConfigurationProperties(prefix = "data") on top of the class, instead of wiring each nested property one by one, by making the code cleaner.
Given all that, here is the final example with explanations:
// File: CustomerConfig.java
#Configuration
// Set property source file path (optional)
#PropertySource("classpath:/data.properties")
// Put prefix = "data" here so that Spring read properties under "data.*"
#ConfigurationProperties(prefix = "data")
public class CustomerConfig {
// Note: Property name here is the same as in the file (data.customer)
// Spring will automatically read and put "data.customer.*" properties into this object
private Customer customer;
// Other configs can be added here too... without wiring one-by-one
public setCustomer(Customer customer){
this.customer = customer;
}
public getCustomer(){
return this.customer;
}
}
That's it, now you have "data.customer.*" properties, loaded and accessible via CustomerConfig.getCustomer().
To integrate it into your service (based on your example code):
// File: CustomerService.java
#Component
#PropertySource("classpath:/data.properties")
public class CustomerService {
#Value("${data.isWaiting:#{false}}")
private Boolean isWaiting;
#Autowired // Inject configs, either with #Autowired or using constructor injection
private CustomerConfig customerConfig;
public void myMethod() {
// Now its available for use
System.out.println(customerConfig.getCustomer().toString());
}
}
This way no "magical hack" is required to read configs into a class.
Take a look at the #ConfigurationProperties documentation/examples, and this post for more useful info.
Note: I'd suggest against using PropertyEditorSupport, since
a) it was built for different purpose, may change in future by breaking the code
b) it requires manual "handling" code inside => possible bugs
Instead, use what was built right for that purpose (Spring already has it), in order to both make the code easier to understand, and to gain possible inner improvements/optimizations which might be done in the future (or present).
Further improvements: Your CustomerService seems to be cluttered with configs (#PropertyService) too. I'd suggest reading those properties via another class too (similarly) then wiring that class here, instead of doing all in the CustomerService.
If you want to use it with lists, there is a workaround using array instead.
Define your property as Customer[] instead of List then:
in ApplicationConfig class:
#Bean
public CustomEditorConfigurer customEditorConfigurer() {
Map<Class<?>, Class<? extends PropertyEditor>> customEditors =
new HashMap<Class<?>, Class<? extends PropertyEditor>>(1);
customEditors.put(Customer.class, CustomerPropertiesEditor.class);
customEditors.put(Customer[].class, CustomerPropertiesEditor.class);
CustomEditorConfigurer configurer = new CustomEditorConfigurer();
configurer.setCustomEditors(customEditors);
return configurer;
}
In CustomerEditor:
public class CustomerEditor extends PropertyEditorSupport {
public static final String DEFAULT_SEPARATOR = ",";
#Override
public void setAsText(String text) {
String[] array = StringUtils.delimitedListToStringArray(text, this.separator);
if (this.emptyArrayAsNull && array.length == 0) {
super.setValue((Object) null);
} else {
if (this.trimValues) {
array = StringUtils.trimArrayElements(array);
}
// Convert String[] to Customer[]
super.setValue(...);
}
}
}
If you want to use an existing converter/constructor, you can just call it within your expression.
For example:
#Value("#{T(org.test.CutomerMap).transform('${serialized.customer}')}")
private Customer customer;

Spring InitBinder: bind empty or null values of a float field as 0

I'm just wondering if it's possible to tell an #InitBinder that empty float values in a form would be converted to 0.
I know that float is a primitive data type but I'd still like to convert null or empty values to 0.
If that is possible, how can i achieve that?
Otherwise I'll just make a workaround using a String instead of a float
Define a subclsss of CustomNumberEditor as
import org.springframework.beans.propertyeditors.CustomNumberEditor;
import org.springframework.util.StringUtils;
public class MyCustomNumberEditor extends CustomNumberEditor {
public MyCustomNumberEditor(Class<? extends Number> numberClass) throws IllegalArgumentException {
super(numberClass, true);
}
#Override
public void setAsText(String text) throws IllegalArgumentException {
if (!StringUtils.hasText(text)) {
setValue(0);
}else {
super.setAsText(text.trim());
}
}
}
Then in your controller class (I create a BaseController for all my application controllers, I need this behavior for all the numeric primitive types in my application, so I simply define this in my BaseController), register binders for the various primitive types.
Note that the constructor parameter of MyCustomNumberEditor must be a subclass of Number, instead of primitive class type.
#InitBinder
public void registerCustomerBinder(WebDataBinder binder) {
binder.registerCustomEditor(double.class, new MyCustomNumberEditor(Double.class));
binder.registerCustomEditor(float.class, new MyCustomNumberEditor(Float.class));
binder.registerCustomEditor(long.class, new MyCustomNumberEditor(Long.class));
binder.registerCustomEditor(int.class, new MyCustomNumberEditor(Integer.class));
....
}
Yes you could always do that .Spring have a CustomNumberEditor which is a customizable property editor for any Number subclass like Integer, Long, Float, Double.It is registered by default by BeanWrapperImpl,but, can be overridden by registering custom instance of it as custom editor.It means you could extend a class like this
public class MyCustomNumberEditor extends CustomNumberEditor{
public MyCustomNumberEditor(Class<? extends Number> numberClass, NumberFormat numberFormat, boolean allowEmpty) throws IllegalArgumentException {
super(numberClass, numberFormat, allowEmpty);
}
public MyCustomNumberEditor(Class<? extends Number> numberClass, boolean allowEmpty) throws IllegalArgumentException {
super(numberClass, allowEmpty);
}
#Override
public String getAsText() {
//return super.getAsText();
return "Your desired text";
}
#Override
public void setAsText(String text) throws IllegalArgumentException {
super.setAsText("set your desired text");
}
}
And then register it normally in you controller:
#InitBinder
public void initBinder(WebDataBinder binder) {
binder.registerCustomEditor(Float.class,new MyCustomNumberEditor(Float.class, true));
}
This should do the task.

Resources