Suppose I have a certain operation that should be available to every process running in Spring MVC.
Say string normalization--
i need to run a method that normalizes the string fields before doing anything else on that form/data.
One thing specific to do is, to normalize the String fields on every input form before
they are dispatched to the back-end services. Likewise, that operation (normalization)
should be run on data from the back-end before it is dispatched to the view component.
One way of doing this that I can think of is:
Code a bean doing it-- the normalization. Then, define this bean somewhere at the top in
the context hierarchy of Spring-- ApplicationContext.xml or WebApplicationContext.xml(?),
so that it will be visible and can be used
accross all the processes/servlets in the application.
Then, Whenever and from wherever needed, invoke that method on the bean defined up there.
Or, inject it to the relevant fields in the bean definitions(?)
In this case, is there a way to call it before or during a HandlerMapping is running? if so, how?
Another i can come up with is:
Code a validator (implement Validator) to run that process and "validate" the String fields for you.
But i dont see how this would be of good help.
From what i know, a validator runs on specific object types. I can define that type generically(?)
but then I'm operating on the fields-- not objects as a whole each.
Coding validator(s) seems too costly to me for this use-- even if it is an option here.
I'm new to Spring. pls bear with me on this.
Related
I have a class that requires parameters provided by the user at runtime. I do this because I like the idea of ensuring the object is always in a valid, ready to use state. However I do not know the parameter values until the user has started using the application which is causing problems with Spring IoC as everything is instantiated at start up.
I think I can work around it this with #Configuration, .getBean calls with arguments, and #Lazy annotations however it feels like I'm kluging (eg. .getBean calls are discouraged)
Is there a nicer way to handle this? I'm thinking I should just lump it and move to having a constructor with no parameters and force a setter method call with the parameters but then I'll have an object sitting around that's in an invalid state.
I have a Spring Batch job that reads in a very large fixed length file and maps it just fine to an object. Validated all of the data in the associated processing task.
Being rather new to Spring and Spring Batch I am wondering if it is possible to get out of the job, a fully populated object to be used in a particular case when I am running the job as part of another process ( that I would like to have access to the data).
I realize that I could do the above without Batch, and it seems to be designed with scope limitations for its purpose.
I could serialize the objects in the processor and go that route but for my immediate satisfaction I am hoping there is a way to get around this.
Thanks
In my #configuration class for the batch processing, I created a class variable (it is a list of the object I want to get back) and instantiated with the no arg constructor.
My Step, ItemReader, LineMapper are setup to use a list for input. The custom FieldSetMapper takes that list instantiated from the constructor as a parameter and adds to the list as the file is read and mapped. Similarly my custom ItemProcessor takes the list as input and returns it.
Finally I created a ReturnObjectList bean that returns the populated list.
In my main I cast the AnnotationConfigApplicationContext getbean to the list of that object type. I am now able to use the list of objects generated from the fixed file in the scope of my main application.
Not sure if this is a healthy work around in terms of how Spring Java config is supposed to work, but it does give me what I need.
I have a page with a dataTable, which is populated based on the query parameters (e.g., username and pagenum). Each entry in the table has a delete commandButton
When the pagenum != 0 and we click delete, the list of records to display is generated during the "apply" phase. During this phase the view parameters have not been set, so the list of records is empty so nothing get's deleted (our delete method doesn't get called)
To work around this I've added a #PostConstruct method that retrieves the query parameters from the Servlet request and sets the values in the bean, so they are available when we get the list of away records, which allows my delete method to be called.
I'm certain that JSF has a better way of handling this scenario and the #PostConstruct work around is a hack.
What is the correct way to implement this scenario, without resorting to a View or Session scoped bean?
Surely there must be a way to just POST the form and delete the appropriate record without having to waste time regenerating the list of records.
What is the correct way to implement this scenario, without resorting to a View or Session scoped bean? Surely there must be a way to just POST the form and delete the appropriate record without having to waste time regenerating the list of records
Sorry, there's no way. At least not when using a standard <h:commandButton> inside a standard <h:dataTable>. This is the consequence of the stateful nature of JSF. JSF just wants to ensure that the view is exactly the same during processing the postback as it was during generating the HTML output.
This is part of JSF's safeguard against tampered requests wherein the enduser/hacker can manipulate the request parameters in such way that it could do hazardful things, e.g. changing the ID of entry to delete, or bypassing the check on rendered attribute, etc. All those things on which you would/should do additional pre-validation anyway if JSF didn't do that for you and are easily overlooked by starters (they would then blame JSF for being insecure instead of themselves). See also Why JSF saves the state of UI components on server? and commandButton/commandLink/ajax action/listener method not invoked or input value not updated.
In case of <h:commandButton> inside <h:dataTable>, JSF simply needs to have the data model available during the apply request values phase, so that it can iterate over the <h:dataTable> in the component tree in order to find the pressed button and queue the action event. If there's no datamodel, then it can't find the pressed button and the action event won't be queued. Normally, this is to be solved by placing the managed bean in the JSF view scope. See also How to choose the right bean scope?
In case of request scoped beans, the <f:viewParam> is indeed not the right tool for the job of preserving the data model before apply request values phase takes place. You need to do the job in a #PostConstruct annotated method instead. The request parameters can in case of JSF managed beans be injected via #ManagedProperty. See also ViewParam vs #ManagedProperty(value = "#{param.id}"). In case of CDI or Spring managed beans, there's no standard annotation available to inject a HTTP request parameter as a bean property. For CDI, the JSF utility library OmniFaces has a #Param for the very purpose. See also OmniFaces #Param showcase. For Spring, you'd need to homegrow it yourself. I, as non-Spring-user have however no idea how to do that. Google also doesn't seem to reveal much.
Alternatively, you can also just put the bean in the view scope by #ViewScoped. It'll then live as long as you postback to the same view. JSF 2.2 has a CDI compatible annotation for that in javax.faces.view package. The one in javax.faces.bean package is the old JSF 2.0/2.1 annotation for #ManagedBean. Spring has no annotation out the box for this as that would otherwise put a dependency on JSF API. You'd need to homegrow it yourself. Google shows several examples.
What is the correct way to implement this scenario
Before executing the any logic on the backing bean, JSF always have to rebuild the view in order to get information about what to execute. For displaying and updating purpose, the best (and correct) solution is certainly the #ViewScoped.
without resorting to a View or Session scoped bean?
If you insist on using #RequestScoped, I'd say there're no correct ways but work-arounds or hacks. One way is to initialise the list in a #PostConstruct method like you've mentioned. Another way may be to use a JavaScript function for the onclick attribute of your delete button. The JS function, for example, will make a call to the server using a URL to request a delete. Or else, you can also use PrimeFace's RemoteCommand for the JS function.
I have a servlet based application which currently uses an injected HashMap of command processors to process a user entered command. This works very well but I need to modify this so that each instance of the command processor is unique.
The new requirements comes from the need to "pipe" the output on one command into another so if the command processors remain a single instance "piping" a list into a list would be problematic.
I still need to be able to map the class that handles the command to the command text.
My first thought was the change the HashMap from mapping the command to an instance of the command processor to mapping it to the class name and using that to instantiate an instance of the class. But that does not work due to the need to configure some of the commands with for example a list of options.
I have looked at making the beans prototypes which would seam to do what I want regarding getting a new instance of the configured bean but I am confused as to how I can map this, was thinking I could use the bean ID.
I am now at the stage of complete confusion and cant think how to do this.
I am aware that the explanation is a little light but this is a reflection of my confusion and I suspect that the greatest help will come from request for clarification which will help to get the head in order.
You could use request-scoped beans:
#Component
#Scope(value=WebApplicationContext.SCOPE_REQUEST,proxyMode=ScopedProxyMode.TARGET_CLASS)
public class CommandProcessor {
}
You can just inject CommandProcessor in your code and Spring will make sure you get different instance for every user request. You also will need CGLIB on your classpath.
If I got your requirements right you either need a factory method in your command class, or a FactoryBean that creates the instances.
I want to be able to set default values for some fields in my domain classes.
Till now I had a class which stored a Map of settings for my whole project, with a task in mind to move this map into a redis database.
The day has come and I moved all the data to redis and created a nice spring bean to get/set the values.
However...
it seems that default values are set on the domain class instance before bean is injected.
This kind of breaks the whole process.
Also... there's an issue with unit tests.
I've created a class which implements the same interface as the spring bean and holds test values. I wanted to inject it into domain classes, but this fails as well.
So right now I'm trying to find a good way to handle externally stored defauls values for my domain classes with ability to run unit tests.
Any thoughts?
There are a few different approaches you could take:
Introduce a separate bean with the default values so that those are supplied in the same way as they were before. In a separate higher level context or later on in application startup, you could then override the bean definition with the one that pulls from the database
Use a BeanPostProcessor or BeanFactoryPostProcessor to specify the default values, then use your new bean for retrieving new values
If neither of these answers is helpful, please post your setup and example code so I can get a clearer picture of what you're trying to do.
What I did in the end:
I've created a class which is connecting to Redis and gets me all the data I require.
For unit testing I've created a copy of this class, it implements the same interface but instead of getting the data from Redis it has a simple Map inside and get's the data from there. In the end it acts the same, but the data is stored internally. So in my unit tests I just inject this Unit test version of this class where appropriate.
Probably not the best solution there is but it worked for me for the last few months.