I having an user details class inside that i placed address class to store the multiple addressess for each user details class. I am using Spring 4.0 for that. Below given the code:
UserDetails class:
#Component("userDetails")
public class UserDetails {
#Resource(name="address")
#Autowired
private List<Address> address;
public List<Address> getAddress() {
return address;
}
#Autowired
public void setAddress(List<Address> address) {
this.address = address;
}
}
Address Class:
#Component("address")
public class Address {
private String area;
public String getArea() {
return area;
}
public void setArea(String area) {
this.area = area;
}
}
In this example, Address.area value need to pass in the run time and then i need to create an object for Address class. Then it need to add in the List address variable present inside UserDetails class. Likewise i need to add n number object in the arrayList then i need to create an object for UserDetails class.
I tried the below code:
public class AppMain {
public static void main(String args[]){
AbstractApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
Address address = (Address)context.getBean("address");
//setting first value:
address.setArea("XXX");
Address address1 = (Address)context.getBean("address");
//setting second value
address1.setArea("YYY");
UserDetails userDetails = (UserDetails)context.getBean("userDetails");
System.out.println("User Size: "+application.getAddress().size());
System.out.println("User Details : "+application.getAddress().get(0).getArea());
System.out.println("User Details : "+application.getAddress().get(1).getArea()); // getting ArrayIndexOutOfBoundException in this line
}
}
partial Output:
User Size: 1
User Details : YYY
Expected Output:
User Size: 2
User Details : XXX
User Details : YYY
Could you please help with this.
It's not entirely clear to me why you would want to create what appear to be domain objects using Spring but it looks like that's what you're doing from your code.
Spring has the concept of Scope that controls what happens when you retrieve a bean from an ApplicationContext. The default Scope is singleton which means you only get a one instance of the bean within the ApplicationContext. This means that your calls context.getBean("address") always return the same object.
As for the wiring that you've performed using the #Component annotation; this occurs when the classpath is scanned (normally when the application starts). At this time Spring instantiates a single instance of each class marked with #Component, that's one Address and one UserDetails. Spring is smart enough to add the single Address to a List before setting the address field but that's all it does.
Your code then retrieves this objects from the ApplicationContext setting the area on the same object twice, hence why the debug statements print as they do.
This explains what's going on with your code, but leaves the question of how to fix it unanswered.
As I said, I can't understand why you would used Spring to build what appears to be a domain model. Domain models, in terms of the instances of each class, are not typically known ahead of time and therefore Spring is not the appropriate tool to use to create such a model (Spring is typically used to wire together the application itself).
You should modify the domain classes' constructors like this:
public Address
{
private String area;
public Address(String area)
{
this.area = area;
}
...
}
public UserDetails
{
private List<Address> addresses;
public UserDetails(Address... addresses)
{
this.addresses = Arrays.asList(addresses);
}
...
}
And then the main method can be re-written:
public static void main(String[] args)
{
UserDetails userDetails = new UserDetails(
new Address("XXX"),
new Address("YYY"),
);
System.out.println("User Size: " + application.getAddress().size());
System.out.println("User Details: " + application.getAddress().get(0).getArea());
System.out.println("User Details: " + application.getAddress().get(1).getArea());
}
Notice that you are getting the same bean twice, so it's impossible that you get two injections in the UserDetails List:
Address address = (Address)context.getBean("address");
...
Address address1 = (Address)context.getBean("address");
Something like this should work:
#Configuration
public class AppConfig{
#Bean
public UserDetails userDetails(){
return new UserDetails();
}
#Bean
public Address addressXXX(){
return new Address();
}
#Bean
public Address addressYYY(){
return new Address();
}
}
Then your code:
Address address = (Address)context.getBean("addressXXX");
//setting first value:
address.setArea("XXX");
Address address1 = (Address)context.getBean("addressYYY");
//setting second value
address1.setArea("YYY");
UserDetails userDetails = (UserDetails)context.getBean("userDetails");
System.out.println("User Size: "+application.getAddress().size());
System.out.println("User Details : "+application.getAddress().get(0).getArea()); //--->XXX
System.out.println("User Details : "+application.getAddress().get(1).getArea()); //--->YYY
Related
How to create Student class object at run time dynamically based on the parameters received in the URL and inject in to WebapplicationContext so the IoC container can auto wire it automaticallly to Access class?
I need to create a bean at run time based on user parameters.
#RestController
public class FunRestController {
#GetMapping("/{id}/{name}")
public String welcomeToBoot(#PathVariable int id, #PathVariable String name) {
// How to create Student class object at run time dynamically based
// on the param received in the URL and can auto wire it dynamically to ***Access*** class below ?
return "Welcome " + name;
}
}
I need to Autowire a run time bean created
public class Access {
#Autowired
Student s;
void print() {
System.out.println(s.name);
}
}
POJO:
public class Student {
public int id;
public String name;
public Student(int id, String name) {
this.id = id;
this.name = name;
}
}
I would suggest not to #Autowired the Student object but instead, pass it as a parameter to a function. Something as follows:
public class Access {
void print(Student s) {
System.out.println(s.name);
}
}
Now you just need to call print() method with the given Student. If you need Access to be a Spring-managed Bean so that you can inject it into your Controller, you would need to annotate it with #Component.
Instead of creating bean, you can create a thread local variable and initialise it as the first thing. Then it'll be available throughout the request / response scope
I've the following model:
public class Users {
public static PlayJongo jongo = Play.current().injector().instanceOf(PlayJongo.class);
public static MongoCollection users() {
return jongo.getCollection("DB.users");
}
..
..
public static Users authenticate(String email, String password) {
Users user = users().findOne("{email: #, removed: false}", email).as(Users.class);
if (user != null) {
if (HomeController.checkPassword(password, user.password)) {
return user;
}
}
return null;
}
..
I use that in my controllers as:
public Result authenticate() {
DynamicForm requestData = Form.form().bindFromRequest();
String email = requestData.get("email").trim();
String password = requestData.get("password").trim();
Users user = Users.authenticate(email, password);
if (user == null) {
flash("danger", "Incorrect email or password.");
return redirect(routes.HomeController.login());
}
session("email", user.getEmail());
session("role", user.getRole());
session("fullname", user.getLastname() + " " + user.getFirstname());
session("id", user.getId().toString());
return redirect(routes.HomeController.index());
}
I tried a lot of combination to use injection with play-jongo without result. E.g.
#Inject
public PlayJongo jongo;
public MongoCollection users() {
return jongo.getCollection("DocBox.users");
}
I enter in a loop of static/non-static referenced context errors. If I remove all static declaration, I'm unable to call Users.method. If I try to inject Users to a controller
public class HomeController extends Controller {
#Inject
public Users users;
.
.
and try to call a Users method:
Users user = users.authenticate(email, password);
I receive a org.jongo.marshall.MarshallingException.
My brain is definitively goes overheating, someone can explain me how to use Injection with play-jongo?
I solve the problem. Now I've a UsersRepository that contains the methods that operate on the mongo collection (authenticate, addUser, et al.). And a Users object that only contains the actual data fields (firstname, lastname, email, etc.).
After that I can inject UsersRepository into my controller and use that one instance everywhere.
Thanks to Greg Methvin, Tech Lead - Play Framework
For example, I have a room
public class Room {
private int id;
private Set<User> users;
}
So I want it to be endpoint for my websocket application. But there may be a lot of rooms and I want each of them could have own URI (for example, rooms/1, rooms/2 etc.)
Evidently, #ServerEnpoint annotaion allows only constants. So, is there any way to make it?
Something like this:
#ServerEndpoint(value = "/rooms/{roomnumber}")
public class....
static Map<String, Session> openSessions = ...
#OnOpen
public void onConnectionOpen(final Session session, #PathParam("roomnumber") final String roomnumber,
...
//store roomnumber in session
session.getUserProperties().put("roomnumber", roomnumber);
openSessions.put( String.valueOf(session.getId()), session )
To only send messages to specific roomnumbers/clients:
// check if session corresponds to the roomnumber
for (Map.Entry<String, Session> entry : openSessions.entrySet()) {
Session s = entry.getValue();
if (s.isOpen() && s.getUserProperties().get("roomnumber").equals(roomnumber_you_want_to_address)) {
...
And when a client disconnects:
#OnClose
public void onConnectionClose(Session session) {
openSessions.remove(session.getId());
}
You can use this per function to map requests with different variables in the same controller
#RequestMapping(value = "/endpoint/{endpointVariable}", method = RequestMethod.GET)
public ReturnDTO getReturnDTO(<params>){
// Here the variable, endpointVariable, will be accessible
// In my experiences its always been an integer, but I'm sure a string
// would be possible. check with debugger
}
http://www.journaldev.com/3358/spring-mvc-requestmapping-annotation-example-with-controller-methods-headers-params-requestparam-pathvariable
I am trying to query spring data elasticsearch repositories for nested properties. My Repository looks like this:
public interface PersonRepository extends
ElasticsearchRepository<Person, Long> {
List<Person> findByAddressZipCode(String zipCode);
}
The domain objects Person and Address (without getters/setters) are defined as follows:
#Document(indexName="person")
public class Person {
#Id
private Long id;
private String name;
#Field(type=FieldType.Nested, store=true, index = FieldIndex.analyzed)
private Address address;
}
public class Address {
private String zipCode;
}
My test saves one Person document and tries to read it with the repository method. But no results are returned. Here is the test method:
#Test
public void testPersonRepo() throws Exception {
Person person = new Person();
person.setName("Rene");
Address address = new Address();
address.setZipCode("30880");
person.setAddress(address);
personRepository.save(person);
elasticsearchTemplate.refresh(Person.class,true);
assertThat(personRepository.findByAddressZipCodeContaining("30880"), hasSize(1));
}
Does spring data elasticsearch support the default spring data query generation?
Elasticsearch indexes the new document asynchronously...near real-time. The default refresh is typically 1s I think. So you must explicitly request a refresh (to force a flush and the document available for search) if you are wanting the document immediately searchable as with a unit test. So your unit test needs to include the ElasticsearchTemplate bean so that you can explicitly call refresh. Make sure you set waitForOperation to true to force a synchronous refresh. See this related answer. Kinda like this:
elasticsearchTemplate.refresh("myindex",true);
I have configured a custom generic service DAO for my spring / hibernate project - the idea being that I can reuse it easily from my controllers.
It essentially looks like this:
public class DefaultService<T> {
private Class<T> e;
public String className(Class<T> e) {
String clip = e.getName();
clip = clip.substring(clip.lastIndexOf('.') + 1, clip.length());
return clip;
}
public List<T> getAll(Integer status) {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("FROM " + className(e) + " WHERE status = " + status);
return query.list();
}
...
Which gets referenced by:
#Autowired
public DefaultService<Address> addressService;
addressService.get(1);
However the String clip = e.getName() line throws a Null pointer exception. I can get this to work if I move the class into the attributes section (so addressService.get(Address.class, 1) but I find this somewhat untidy, especially when there are multiple different classes being called upon.
Is there some way to get the class to generate a value correctly without repeatedly adding it into all my functions?
Thanks in advance.
I did something similar, you need the generic class to be a constructor argument as well, mine uses hibernate entities, but you could pass in the string of table name.
public class DomainRepository<T> {
#Resource(name = "sessionFactory")
protected SessionFactory sessionFactory;
public DomainRepository(Class genericType) {
this.genericType = genericType;
}
#Transactional(readOnly = true)
public T get(final long id) {
return (T) sessionFactory.getCurrentSession().get(genericType, id);
}
You can then subclass (if you need to) to customize or simply set up you bean in the spring config like below t :
<bean id="tagRepository" class="com.yourcompnay.data.DomainRepository">
<constructor-arg value="com.yourcompnay.domain.Tag"/>
</bean>
So in your code you could then reference tagRepository like so (no other cod eis needed than that posted above, and below) :
#Resource(name = "tagRepository")
private DomainRepository<Tag> tagRepository;
Also, I would call it a repository not a service, a service deals with different types and their interactions (not just one). And for specifically your example using SQL strings :
public final String tableName;
public DomainRepository(String tableName) {
this.tableName = tableName;
}
public List<T> getAll(Integer status) {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("FROM " + tableName + " WHERE status = " + status);
return query.list();
}
and have your beans defined like so
<bean id="addressRepository" class="com.yourcompnay.data.DomainRepository">
<constructor-arg value="address"/>
</bean>
And then you can alsow create subclasses youself where necessary :
public class PersonRepository extends DomainRepository<Person> {
public PersonRepository(){
super("person"); //assumes table name is person
}
As I understand you got NPE because you did not set any value for this field.
So you can resolve this problem by 2 ways:
Set manually class object as in comment NimChimpsky.
Get class type dynamically. E.g, if you use Spring try this one:
protected Class getEntityClass() {
return GenericTypeResolver.resolveTypeArguments(getClass(), DefaultService.class)[0];
}
or some workaround here
It's better to define a specific class for Address service
public class AddressService extends DefaultService<Address>{
public String getClassName(){
return "Address";
}
}
where
public String getClassName();
is an abstract method declared in DefaultService, and used (like your method className()) in your data access logic.
Using this approach, you will be able to add specific data access logic (example, getUsersByAddress)