Use builder pattern with JSF? - java

I'm just trying to port a tiny desktop app of mine to web.
Since days I'm trying to find out how I can make use of the builder pattern (I already have) in JSF?
Or do I have to refactor to Bean Entities and cannot use Builder?
Consider following code:
public class MyFacade {
private MyClass bar;
publich save() {
crudService.persist(bar);
}
}
<h:inputText id="name" value="#{MyFacade.bar.property}" />
//submit button
I want so store text field values to my DB / entities of course. Which is quite easy if you have normal backend beans.
But what if I create my objects like the following?
MyClass newObject = MyClass.Builder("mandatory field").setOptionalFields("optional field").build();
How can I make use of this in jsf, if at all?
Thanks lot

If I understand you correctly you should introduce another type of beans into your JSF application just for interaction with your view and leave your facade (dao) beans as they are.
You would end up with something like this:
#RequestScoped
public class YourBean{
#Inject
private MyFacade facade;
//bean created with builder
private MyBean bean;
public String someMethodExecutedwithEL(){
//build your object here and save it with the dao layer
facade.save(objectFromBuilder);
}
#PostConstruct
public void init(){
//create your bean with builder pattern
}
}
Example above is of course just a scribbled idea, the point is that there is nothing stopping you from creating your objects using builder pattern, just introduce another layer for separation of concerns.
EDIT:
If you want to create your objects before they are used on the jsf page you can add method annotated #PostConstruct
(updated the code sample as well)
Possibilities are endless.
Tip - consider naming your classes and variables using standard naming conventions and common sense.

Related

When is DI not suitable to use

I am reading a blog about DI and there are some sentences that I don't understand.
What does it mean that DI is a singleton object at runtime and only those objects within the scanning range of spring(with #Component) can use DI by annotation(#Autowired), while others created by new cannot use DI by annotation?
cannot use DI because Father can be created by new.
public class Father{
private SonRepository sonRepo;
private Son getSon(){return sonRepo.getByFatherId(this.id);}
public Father(SonRepository sonRepo){this.sonRepo = sonRepo;}
}
can use DI because FatherFactory is a singleton object generated by the system.
#Component
public class FatherFactory{
private SonRepository sonRepo;
#Autowired
public FatherFactory(SonRepository sonRepo){}
public Father createFather(){
return new Father(sonRepo);
}
It means:
Spring is responsible for managing the scope of objects. You don't need boilerplate like final classes with static getInstance methods. (For how singletons work in Spring see this question.)
Spring can only autowire things into the components if those components are somewhere that it has been told to look, component-scanning is how spring searches for the components that it needs to wire up. You give spring the starting points by specifying what package names it needs to start searching from. If a component is not within one of those directories, then Spring can't manage it.

Spring equivalent of EJB Singleton to maintain the state

Currently I'm working on a JSF2 + Spring application. And I need to have one component, which I would be able to autowire when needed and read/write the state (safely) from/to it.
In EJB I would do it as follows:
#Singleton
#ConcurrencyManagement(ConcurrencyManagementType.CONTAINER)
public class LocaleManager {
private String currentLanguage;
#Lock(LockType.READ)
public String getCurrentLanguage() {
return currentLanguage;
}
#Lock(LockType.WRITE)
public void setCurrentLanguage(String currentLanguage) {
this.currentLanguage = currentLanguage;
}
}
How can I achieve this in Spring? Thanks!
EDIT: One important thing is that application has multiple Maven modules and I need this in "core" module which doesn't depend on spring-web. I need the language information in DTO assemblers, where I would like to use only string values relevant to the current locale set in JSF. Entity has a set of translations for various languages (each DB table has own translation table). In the corresponding DTO I would like to have just e.g. "String description", instead of "Set<ItemTranslation> description".
In Spring the scope of the bean says how the instances are created. I suggest you to check out the following tutorial:
http://www.mkyong.com/spring/spring-bean-scopes-examples/

Passing state to CDI-container-managed beans

I'm using Spring for this project, but I've had the same problem with Guice as well.
Basically, I have functionality that requires both stateless helpers and state data to operate on.
public class AwesomeDoer {
#Inject
private Helper helper; //stateless
...
public void doAwesome(int state) {
helper.help(state)
}
}
This looks pretty good, until doAwesome has 5 parameters and is being called 1000 times, but 3 of the arguments are the same value every time while a fourth argument might change only a handful of times. Changing the appropriate parameters to fields is the obvious solution. However, this requires you to sacrifice either the CDI management of this class, or else you have to have an initializer or setters to fill in the state after Spring does its thing.
I've usually gotten around this by creating a factory managed by Spring, ie
public class AwesomeFactory {
#Inject
private Helper helper;
public AwesomeDoer getAwesomeDoer(int state) {
return new AwesomeDoer(helper, state);
}
}
But again, this means that my AwesomeDoer is no longer being managed by Spring, and it requires me to write yet another layer of non-business logic. It's also easy to imagine this approach leading to the creation of an AwesomeFactoryFactory, etc, which always makes me die a little on the inside.
So does anybody have a cleaner way of doing this?
You can mark your bean using #Configurable from Spring and create it using new AwesomeDoer and passing the parameters in your constructor. #Configurable makes you create the bean on demand and the bean will be managed by Spring to fire the injections like #Autowired.
More info: Create a bean using new keyword and managed by Spring, check the section at the bottom.

Autowiring in classes without RequestMapping

I am working on three different tables. I am using Hibernate to query these tables. I implemented successfully the DAO and the service layers, but i have few problems with the controller package. Here is my code, my controller package contains 3 classes , each should handle a table (i have 3 tables as i said before).
#Controller
public class Ods_Gis_Actel_Controller {
Param_Gis_Actel_Controller Param = new Param_Gis_Actel_Controller();
Tbl_Dim_Actel_Controller Dim = new Tbl_Dim_Actel_Controller();
#Autowired
Ods_Gis_Actel_metier service;
#RequestMapping(value="/index")
public String pageIndex(Model model)
{
addOdsTable(model);
Param.addParamTable(model);
Dim.addDimTable(model);
return "Affichage";
}
public void addOdsTable(Model model)
{
model.addAttribute("listeOds",service.getAll());
}
}
#Controller
public class Param_Gis_Actel_Controller {
#Autowired
Param_Gis_Actel_metier service;
public void addParamTable(Model model)
{
model.addAttribute("listeParam",service.getAll());
}
}
#Controller
public class Tbl_Dim_Actel_Controller {
#Autowired
Tbl_Dim_Actel_metier service;
public void addDimTable(Model model)
{
model.addAttribute("listeDim",service.getAll());
}
}
The request mapping is done in the 1st class, whose method calls 2 other methods from the other classes. But it seems, that the autowiring works only in the class, where the RequestMapping is performed.
Is this true?
how can i use the other methods from the classes which don't contain the RequestMapping if the autowiring doesn't work for them?
I gone through your problem , I think you are not so much aware the objective of #Controller , #RequestMapping . So First of all you need to know , why we use #Controller?, this is used to give business logic to your request. When request is hited from user , then your DispatcherServlet match the url from your request to value of RequestMapping annotation of all defined controller. And according to that , the matched mapping method is called and further procees done by framework. Now come to #Autowire, this is used to load the bean class definition from the xml configuration. So the #Autowire and #RequestMapping having different objective . So it's wrong to say here that the
**autowiring** works only in the class where the RequestMapping is performed.
Now your second question , How you can use simple class? there are two ways to achieve that as far as I know,
1) To create the Object of that class inside your class as you done in your code
2) To create the instance of that class using factory-method.
for the second point , you have to first define your class inside the configuration file by following the below format
<bean id="paramGis" class="<whatever_package_detail>.Param_Gis_Actel_Controller" factory-method="createInstance"/>
here one things you have to care that this method should be static .
and your class would look like that
#Service
public class Param_Gis_Actel_Controller {
private static Param_Gis_Actel_Controller paramGis;
public static Param_Gis_Actel_Controller createInstance(){
if(paramGis==null){
return new Param_Gis_Actel_Controller();
}
return paramGis;
}
public void addParamTable(Model model)
{
model.addAttribute("listeParam",service.getAll());
}
}
If you are still getting problem let me know.
I think you are having difficulties with the Java/Spring way. We don't use #Controller/#Autowired like that.
It's kind of hard to explain shortly (I strongly recommend you read the official document for that), but in short, you shouldn't create a Controller object inside another controller. The objects with annotation marks (#Controller, #Service...) should be generated and managed by Spring. At initiation time they will be injected with the #Autowired services by "Spring" way. Of courses you can intervene into that process, but by other special methods.
P/s: your naming convention is not for Java ;). If you create a program for personal use it maybe ok, but you will have difficult times collaborating with other Java developers.
Through method name as default one for access that particular method or use #Qualifier annotations.

Using guice for a framework with injected classes, proper way to initialize?

I'm trying to write a framework where arbitrary bean classes are injected with classes from my API, and they can interact with both those classes as well have triggered callbacks based on defined annotations. Here's an example bean:
#Experiment
static class TestExperiment {
private final HITWorker worker;
private final ExperimentLog log;
private final ExperimentController controller;
#Inject
public TestExperiment(
HITWorker worker,
ExperimentLog expLog,
ExperimentController controller
) {
this.worker = worker;
this.expLog = expLog;
this.controller = controller;
}
#SomeCallback
void callMeBack() {
... do something
log.print("I did something");
}
}
I'm trying to use Guice to inject these beans and handle the interdependencies between the injected classes. However, I have two problems:
One of the classes I pass in (HITWorker) is already instantiated. I couldn't see how to move this to a Provider without significantly complicating my code. It is also persistent, but not to the Guice-defined session or request scope, so I am managing it myself for now. (Maybe if the other issues are overcome I can try to put this in a provider.)
More importantly, I need a reference to the other injected classes so I can do appropriate things to them. When Guice injects them, I can't access them because the bean class is arbitrary.
Here's some really bad code for what I basically need to do, which I am sure is violating all the proper dependency injection concepts. Note that hitw is the only instance that I need to pass in, but I'm creating the other dependent objects as well because I need references to them. With this code, I'm basically only using Guice for its reflection code, not its dependency resolution.
private void initExperiment(final HITWorkerImpl hitw, final String expId) {
final ExperimentLogImpl log = new ExperimentLogImpl();
final ExperimentControllerImpl cont = new ExperimentControllerImpl(log, expManager);
// Create an experiment instance with specific binding to this HITWorker
Injector child = injector.createChildInjector(new AbstractModule() {
#Override
protected void configure() {
bind(HITWorker.class).toInstance(hitw);
bind(ExperimentLog.class).toInstance(log);
bind(ExperimentController.class).toInstance(cont);
}
});
Object experimentBean = child.getInstance(expClass);
expManager.processExperiment(expId, experimentBean);
// Initialize controller, which also initializes the log
cont.initialize(expId);
expManager.triggerStart(expId);
tracker.newExperimentStarted(expId, hitw, cont.getStartTime());
}
Am I screwed and just have to write my own injection code, or is there a way to do this properly? Also, should I just forget about constructor injection for these bean classes, since I don't know what they contain exactly anyway? Is there any way to get the dependencies if I am asking Guice to inject the bean instead of doing it myself?
For context, I've been reading the Guice docs and looking at examples for several days about this, to no avail. I don't think I'm a complete programming idiot, but I can't figure out how to do this properly!
Your "experiment" seems to be something like a "request" in the sense that it has a defined lifecycle and some associated stuff the experiment can pull in at will.
Therefore I think you should wrap all that into a custom scope as described in the docs about Custom Scopes. This matches your case in several points:
You can "seed" the scope with some objects (your HITWorker)
The lifecycle: do "enter scope" before you setup the experiment and "exit scope" after you finished your work.
Access to "shared" stuff like ExperimentLog and ExperimentController: Bind them to the scope. Then both the framework and the experiment instance can simple #Inject them and get the same instance.

Categories