Professional Documents
Culture Documents
For spring to process annotations, add the following lines in your application-context.xml
file.
<context:annotation-config />
<context:component-scan base-package="...specify your package
name..." />
Spring supports both Annotation based and XML based configurations. You can
even mix them together. Annotation injection is performed before XML
injection, thus the latter configuration will override the former for properties
wired through both approaches.
@Service
Annotate all your service classes with @Service. All your business logic should be in Service
classes.
@Service
public class CompanyServiceImpl implements CompanyService {
...
}
@Repository
Annotate all your DAO classes with @Repository. All your database access logic should be
in DAO classes.
@Repository
public class CompanyDAOImpl implements CompanyDAO {
...
}
@Component
Annotate your other components (for example REST resource classes) with @Component.
@Component
public class ContactResource {
...
}
@Component is a generic stereotype for any Spring-managed component. @Repository,
@Service, and @Controller are specializations of @Component for more specific use cases,
for example, in the persistence, service, and presentation layers, respectively.
@Autowired
Let Spring auto-wire other beans into your classes using @Autowired annotation.
@Service
public class CompanyServiceImpl implements CompanyService {
@Autowired
private CompanyDAO companyDAO;
...
}
Spring beans can be wired by name or by type.
Beans that are themselves defined as a collection or map type cannot be injected
through @Autowired, because type matching is not properly applicable to them.
Use @Resource for such beans, referring to the specific collection or map bean
by unique name.
@Transactional
@Autowired
private CompanyDAO companyDAO;
@Transactional
public Company findByName(String name) {
These default settings can be changed using various properties of the @Transactional spring
annotation.
Specifying the @Transactional annotation on the bean class means that it applies
to all applicable business methods of the class. Specifying the annotation on a
method applies it to that method only. If the annotation is applied at both the
class and the method level, the method value overrides if the two disagree.
@Scope
As with Spring-managed components in general, the default and most common scope for
autodetected components is singleton. To change this default behavior, use @Scope spring
annotation.
@Component
@Scope("request")
public class ContactResource {
...
}
Similarly, you can annotate your component with @Scope("prototype") for beans with
prototype scopes.
Please note that the dependencies are resolved at instantiation time. For
prototype scope, it does NOT create a new instance at runtime more than once. It
is only during instantiation that each bean is injected with a separate instance of
prototype bean.
@RequestMapping
You use the @RequestMapping spring annotation to map URLs onto an entire class or a
particular handler method. Typically the class-level annotation maps a specific request path
(or path pattern) onto a form controller, with additional method-level annotations narrowing
the primary mapping.
@Controller
@RequestMapping("/company")
public class CompanyController {
@Autowired
private CompanyService companyService;
...
}
@PathVariable
You can use the @PathVariable spring annotation on a method argument to bind it to the
value of a URI template variable. In our example below, a request path of /company/techferry
will bind companyName variable with 'techferry' value.
@Controller
@RequestMapping("/company")
public class CompanyController {
@Autowired
private CompanyService companyService;
@RequestMapping("{companyName}")
public String getCompany(Map<String, Object> map,
@PathVariable String companyName) {
Company company = companyService.findByName(companyName);
map.put("company", company);
return "company";
}
...
}
@RequestParam
You can bind request parameters to method variables using spring annotation
@RequestParam.
@Controller
@RequestMapping("/company")
public class CompanyController {
@Autowired
private CompanyService companyService;
@RequestMapping("/companyList")
public String listCompanies(Map<String, Object> map,
@RequestParam int pageNum) {
map.put("pageNum", pageNum);
map.put("companyList", companyService.listCompanies(pageNum));
return "companyList";
}
...
}
Similarly, you can use spring annotation @RequestHeader to bind request headers.
@ModelAttribute
@Autowired
private CompanyService companyService;
@RequestMapping("/add")
public String saveNewCompany(@ModelAttribute Company company) {
companyService.add(company);
return "redirect:" + company.getName();
}
...
}
@SessionAttributes
@SessionAttributes spring annotation declares session attributes. This will typically list the
names of model attributes which should be transparently stored in the session, serving as
form-backing beans between subsequent requests.
@Controller
@RequestMapping("/company")
@SessionAttributes("company")
public class CompanyController {
@Autowired
private CompanyService companyService;
...
}
@SessionAttribute works as follows:
@SessionAttribute is initialized when you put the corresponding attribute into model
(either explicitly or using @ModelAttribute-annotated method).
@SessionAttribute is updated by the data from HTTP parameters when controller
method with the corresponding model attribute in its signature is invoked.
@SessionAttributes are cleared when you call setComplete() on SessionStatus object
passed into controller method as an argument.
The following listing illustrate these concepts. It is also an example for pre-populating Model
objects.
@Controller
@RequestMapping("/owners/{ownerId}/pets/{petId}/edit")
@SessionAttributes("pet")
public class EditPetForm {
@ModelAttribute("types")
@RequestMapping(method = RequestMethod.POST)
public String processSubmit(@ModelAttribute("pet") Pet pet,
BindingResult result, SessionStatus status) {
new PetValidator().validate(pet, result);
if (result.hasErrors()) {
return "petForm";
}else {
this.clinic.storePet(pet);
status.setComplete();
return "redirect:owner.do?ownerId="
+ pet.getOwner().getId();
}
}
}
Using Spring Security @PreAuthorize annotation, you can authorize or deny a functionality.
In our example below, only a user with Admin role has the access to delete a contact.
@Transactional
@PreAuthorize("hasRole('ROLE_ADMIN')")
public void removeContact(Integer id) {
contactDAO.removeContact(id);
}
@Entity
1@Entity
2public class Company implements Serializable {
3...
4}
@Table
Specify the database table this Entity maps to using the name attribute of @Table annotation.
In the example below, the data will be stored in 'company' table in the database.
1@Entity
2@Table(name = "company")
3public class Company implements Serializable {
...
4}
5
@Column
@Id
@GeneratedValue
@Version
Control versioning or concurrency using @Version annotation.
1
@Entity
2 @Table(name = "company")
3 public class Company implements Serializable {
4
5 @Version
6 @Column(name = "version")
7 private Date version;
8
...
9 }
10
@OrderBy
Sort your data using @OrderBy annotation. In example below, it will sort all contacts in a
company by their firstname in ascending order.
1@OrderBy("firstName asc")
2private Set contacts;
@Transient
@Lob
Tables company and companyDetail have shared values for primary key. It is a one-
to-one assoication.
Tables contact and contactDetail are linked through a foreign key. It is also a one to
one association.
Tables contact and company are linked through a foriegn key in many-to-one
association with contact being the owner.
Tables company and companyStatus are linked through a foreign key in many-to-one
association with company being the owner.
@OneToOne
The rationale to have one relationship as uni-directional and other as bi-directional in this
tutorial is to illustrate both concepts and their usage. You can opt for uni-directional or bi-
directional relationships to suit your needs.
@ManyToOne
The two examples below illustrate many-to-one relationships. Contact to Company and
Company to CompanyStatus. Many contacts can belong to a company. Similary many
companies can share the same status (Lead, Prospect, Customer) - there will be many
companies that are currently leads.
1 @Entity
2 @Table(name = "contact")
3 public class Contact implements Serializable {
4 @ManyToOne
5 @JoinColumn(name = "companyId")
6 private Company company;
7
8 ...
9
10 }
11
12@Entity
@Table(name = "company")
13public class Company implements Serializable {
14
15 @ManyToOne
16 @JoinColumn(name = "statusId")
17 private CompanyStatus status;
18
19 ...
20
}
21
22
23
@OneToMany
Please see the many-to-one relationship between Contact and Company above. Company to
Contact will be a one-to-many relationship. The owner of this relationship is Contact and
hence we will use 'mappedBy' attribute in Company to make it bi-directional relationship.
1
@Entity
2 @Table(name = "company")
3 public class Company implements Serializable {
4
5 @OneToMany(mappedBy = "company", fetch = FetchType.EAGER)
6 @OrderBy("firstName asc")
private Set contacts;
7
8
...
9
10 }
11
Again, for this tutorial, we have kept Company to CompanyStatus relationship as uni-
directional.
@ManyToMany
@PrimaryKeyJoinColumn
@PrimaryKeyJoinColumn annotation is used for associated entities sharing the same primary
key. See OneToOne section for details.
1 @Entity
2 @Table(name = "company")
public class Company implements Serializable {
3
4 @Id
5 @Column(name = "id")
6 @GeneratedValue
7 private int id;
8
@OneToOne(cascade = CascadeType.MERGE)
9 @PrimaryKeyJoinColumn
10 private CompanyDetail companyDetail;
11
12 ...
13}
14
15
@JoinColumn
Use @JoinColumn annotation for one-to-one or many-to-one associations when foreign key
is held by one of the entities. We can use @OneToOne or @ManyToOne mappedBy attribute
for bi-directional relations. Also see OneToOne and ManyToOne sections for more details.
1@ManyToOne
2@JoinColumn(name = "statusId")
3private CompanyStatus status;
@JoinTable
Use @JoinTable and mappedBy for entities linked through an association table.
@MapsId
Persist two entities with shared key (when one entity holds a foreign key to the other) using
@MapsId annotation. See OneToOne section for details.
1@OneToOne
2@MapsId
3@JoinColumn(name = "contactId")
4private Contact contact;
table per class hierarchy - single table per Class Hierarchy Strategy: the <subclass>
element in Hibernate
1 @Entity
2 @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="planetype",
3 discriminatorType=DiscriminatorType.STRING )
4
5 @DiscriminatorValue("Plane")
6 public class Plane { ... }
7
8 @Entity
9 @DiscriminatorValue("A320")
public class A320 extends Plane { ... }
10
1@Entity
2@Inheritance(strategy=InheritanceType.JOINED)
3public class Boat implements Serializable { ... }
4
5@Entity
6@PrimaryKeyJoinColumn
public class Ferry extends Boat { ... }
7
table per concrete class - table per Class Strategy: the <union-class> element in
Hibernate
1 @Entity
2 @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
3 public class Flight implements Serializable { ... }
Note: This strategy does not support the IDENTITY generator strategy:
the id has to be shared across several tables. Consequently, when using
this strategy, you should not use AUTO nor IDENTITY.
@Inheritance
@DiscriminatorColumn
@DiscriminatorValue
As stated earlier in Example Application, we are using Jersey for RESTful Web services and
JAX-RS annotations.
REST follows one-to-one mapping between create, read, update, and delete
(CRUD) operations and HTTP methods.
@GET
@Produces annotation specifies the type of output this method (or web service) will produce.
1@GET
2@Produces("application/xml")
3public Contact getXML() {
4 ...
5}
1@GET
2@Produces("application/json")
3public Contact getJSON() {
4 ...
5}
@Path
@Path annotation specify the URL path on which this method will be invoked.
1@GET
2@Produces("application/xml")
3@Path("xml/{firstName}")
4public Contact getXML() {
5 ...
}
6
@PathParam
@QueryParam
Request parameters in query string can be accessed using @QueryParam annotation as shown
below.
1@GET
@Produces("application/json")
2@Path("json/companyList")
3public CompanyList getJSON(@QueryParam("start") int start,
4@QueryParam("limit") int limit) {
CompanyList list = new CompanyList(companyService.listCompanies(start,
5limit));
6 return list;
7}
The example above returns a list of companies (with server side pagination) which can be
displayed with rich clients implemented using Ext-js or jQuery. You can read more more
about setting up ExtJS grid panel with remote sorting and pagination using Hibernate.
@POST
@Consumes
The @Consumes annotation is used to specify the MIME media types a REST resource can
consume.
1
@PUT
2@Consumes("application/json")
3@Produces("application/json")
4@Path("{contactId}")
5public RestResponse<Contact> update(Contact contact) {
6...
}
7
@FormParam
The REST resources will usually consume XML/JSON for the complete Entity Bean.
Sometimes, you may want to read parameters sent in POST requests directly and you can do
that using @FormParam annotation. GET Request query parameters can be accessed using
@QueryParam annotation.
1@POST
2public String save(@FormParam("firstName") String firstName,
3 @FormParam("lastName") String lastName) {
4 ...
}
5
@PUT
@DELETE
As stated earlier in Example Application, we are using JAXB to convert our Entities to XML or JSON
format, so our rich clients like Ext-js or jQuery can easily process and present the data.
@XmlRootElement
Define the root element for the XML to be produced with @XmlRootElement JAXB annotation. The
name of the root XML element is derived from the class name.
1@XmlRootElement
2public class Contact implements Serializable {
3...
}
4
You can also specify the name of the root element of the XML using its name attribute, for example
@XmlRootElement(name = "CompanyContact")
@XmlElement
Annotate all fields that needs to be included in XML/JSON output with @XMLElement.
1 @XmlElement
2 public String getName() {
3 return name;
4 }
Either annotate all fields or all getter methods in your Entity bean. A mix of both is not
supported. Add @XmlAccessorType(XmlAccessType.FIELD) at the class level if you want
to annotate private fields instead of getter methods.
@XmlType
Specify the order in which XML elements or JSON output will be produced.
1@XmlRootElement
4...
5}
1
<contact>
2 <id>38</id>
3 <firstname>FirstName</firstname>
4 <lastname>LastName</lastname>
5 <email>dummyEmail@techferry.com</email>
<telephone>1111111111</telephone>
6
</contact>
7
2"email":"dummyEmail@techferry.com","telephone":"1111111111"}
@XmlTransient
Annotate fields that we do not want to be included in XML or JSON output with @XMLTransient.
1@XmlTransient
3 return version;
4}
@XmlSeeAlso
Use @XmlSeeAlso annotation when we want another Entity bean included in the XML output. In our
example below, CompanyList bean refers to Company bean and the XML output should include XML
generated from Company Entity too.
1
@XmlRootElement(name = "List")
2
@XmlSeeAlso(Company.class)
3 public class CompanyList {
5 @XmlElement(name = "companyList")
7 return list;
}
8
...
9
}
10
To include more than 1 classes, we can use @XmlSeeAlso JAXB annotation as:
@XmlSeeAlso({ A.class, B.class })
If you have reviewed both Hibernate - JPA Annotations and JAXB Annotations, the following snippet
illustrates usage of both JAXB and JPA annotations in the same entity Contact.
1 @Entity
2 @Table(name = "CONTACT")
@XmlRootElement
3
@XmlType(propOrder = { "id", "firstName", "lastName", "email",
4 "telephone" })
5 public class Contact implements Serializable {
7 @Id
8 @Column(name = "ID")
@GeneratedValue
9
private Integer id;
10
11
@Column(name = "firstName")
12
private String firstName;
13
14
@Column(name = "lastName")
15 private String lastName;
16
17 @Column(name = "EMAIL")
18 private String email;
19
20 @Column(name = "TELEPHONE")
22
@Version
23
@Column(name = "version")
24
private Date version;
25
26
@ManyToOne
27
@JoinColumn(name = "companyId")
28 private Company company;
29
33 @XmlTransient
return company;
35
}
36
37
public void setCompany(Company company) {
38
this.company = company;
39
}
40
41 @XmlTransient
42 public ContactDetail getContactDetail() {
43 return contactDetail;
44 }
45
this.contactDetail = contactDetail;
47
}
48
49
@XmlTransient
50
public Date getVersion() {
51
return version;
52 }
53
55 this.version = version;
56 }
57
58 @XmlElement
62
63 public void setId(Integer id) {
64 this.id = id;
}
65
66
@XmlElement
67
public String getFirstName() {
68
return firstName;
69
}
70
74
75 @XmlElement
return lastName;
77
}
78
79
public void setLastName(String lastName) {
80
this.lastName = lastName;
81
}
82
83 @XmlElement
84 public String getEmail() {
85 return email;
86 }
87
this.email = email;
89
}
90
91
@XmlElement
92
public String getTelephone() {
93
94 return telephone;
95 }
96
public void setTelephone(String telephone) {
97
this.telephone = telephone;
98
}
99
100
}
101
102
103
104
105
106
107
This section assumes that you have reviewed RESTful JAX-RS Annotations, Hibernate - JPA
Annotations and JAXB Annotations. Also see the section above on using JAXB and JPA Annotations in
Conjunction.
Now that you have an entity bean containing both JAXB and JPA Annotations which is capable of
doing data exchange with database and coverting it to required JSON/XML format, the next step is
to send this data to rich clients using jQuery or Ext-js. In your REST based web-service methods,
return the Contact entity bean as shown below. Jersey, JAXB will take care of data conversion and
appropriate response generation.
1
@GET
2@Produces("application/xml")
3@Path("xml/{firstName}")
return contact;
6
}
7
@GET
1
@Produces("application/json")
2@Path("json/{firstName}")
We are now ready to test our Spring based application using jUnit and Spring Unit testing
framework. The following jUnit and Spring annotations will be used to accomplish this.
@RunWith
When a class is annotated with @RunWith or extends a class annotated with @RunWith, JUnit will
invoke the class it references to run the tests in that class instead of the runner built into JUnit. Let
us configure jUnit to use Spring jUnit Class runner.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/spring-servlet-test.xml"})
public class CompanyServiceTest {
...
}
@ContextConfiguration
Set the spring ApplicationContext for your test classes using @ContextConfiguration annotation.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/spring-servlet-test.xml"})
public class CompanyServiceTest {
...
}
@Test
Annotate all your jUnit unit tests with @Test. Also note that we can wire other spring beans in our
jUnit test classes using @Autowired annotation.
@Autowired
private CompanyService companyService;
@Test
public void testFindByName() {
Company company = companyService.findByName("techferry");
if (company != null) {
assertEquals("prospect", company.getStatus().getName());
}
}
@DirtiesContext
Annotate @DirtiesContext to indicate that it dirties the ApplicationContext. This will trigger context
reloading before execution of next test.
@Timed
Indicates that the annotated test method must finish execution in a specified time period (in
milliseconds). If the text execution time exceeds the specified time period, the test fails.
@Timed(millis=1000)