-
Notifications
You must be signed in to change notification settings - Fork 124
Defining Scala Beans in Spring XML
By default, Scala classes do not follow the JavaBeans property contract (eg. String getFoo()
and void setFoo(String)
).
Instead, Scala has its own property contract: "getters" aren't prefixed by get
, but rather use the field name as method name (eg. String foo()
).
Scala setters suffix the field name with _$eq
(void foo_$eq(String)
).
For example, this class:
class Person(val firstName: String, val lastName: String) {
var middleName: String = _
}
will look like this from the perspective of Java:
public class JavaPerson {
private final String firstName;
private String middleName;
private final String lastName;
public JavaPerson(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() {
return firstName;
}
public String lastName() {
return lastName;
}
public String middleName() {
return middleName;
}
public void middleName_$eq(String middleName) {
this.middleName = middleName;
}
}
As you can see, the Scala compiler generated "getters" for all the vals, and also a "setter" for the var middleName
.
The Spring container only supports bean properties that follow the JavaBean contract. In order to wire up Scala classes as Spring beans, one has to choose between three different solutions described below.
The easiest and preferred way to wire up a Scala Bean in a Spring XML application context is to simply use constructor injection.
For example, imagine we have the following Scala class:
class Person(val firstName: String, val lastName: String)
You can wire up this class like so:
<bean id="person" class="Person">
<constructor-arg value="John"/>
<constructor-arg value="Doe"/>
</bean>
Or even shorter, by using the c namespace:
<bean id="constructor" class="Person" c:firstName="John" c:lastName="Doe"/>
Note that, by using constructor injection in combination with a val
, we also made the Person
class immutable.
Functional languages, such as Scala, encourage immutable data structures.
As such, constructor injection is preferred when using Spring in Scala.
As stated above, by default Scala classes do not follow the JavaBeans contract for properties.
However, you can instruct the Scala compiler to generate JavaBeans getters and setters by using the @scala.reflect.BeanProperty
annotation.
For example, the following class:
class Person(val firstName: String, val lastName: String) {
@BeanProperty var middleName: String = _
}
will look like this from the perspective of Java:
public class JavaPerson {
private final String firstName;
private String middleName;
private final String lastName;
public JavaPerson(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String firstName() {
return firstName;
}
public String lastName() {
return lastName;
}
public String middleName() {
return middleName;
}
public void middleName_$eq(String middleName) {
this.middleName = middleName;
}
public String getMiddleName() {
return middleName;
}
public void setMiddleName(String middleName) {
this.middleName = middleName;
}
}
Note the addition of the getter and setter at the end of the class.
Since this class now follows the JavaBean contract, we can now wire it up in a standard XML bean definition:
<bean id="person" class="Person" c:firstName="John" c:lastName="Doe">
<property name="middleName" value="de la"/>
</bean>
As alternative to using the @BeanProperty
annotation, as of version 3.2, Spring supports arbitrary getters and setters using the BeanInfoFactory
strategy interface.
The Spring Scala project contains an implementation of this interface that supports Scala getters and setters.
This implementation will automatically be detected by Spring, there is no need for additional configuration.
In practical terms, this means that putting the Spring Scala jar on the class path will enable support for Scala properties.
For instance, we can wire up the following class:
class Person(val firstName: String, val lastName: String) {
var middleName: String = _
}
like so:
<bean id="person" class="Person" c:firstName="John" c:lastName="Doe">
<property name="middleName" value="de la"/>
</bean>
Note the lack of @BeanProperty
on the middle name field.
Because the use of Spring Scala, the Spring container will support the Scala properties out of the box.
In summary, the preferred way of wiring up Scala classes in Spring XML is to use constructor injection in combination with vals.
If property injection is required, use Spring Scala to enable support for Scala setters (requires Spring 3.2+).
If Spring Scala cannot be used, use @BeanProperty
.
Finally, you can also use Function Bean Configuration to define your beans in Scala code rather than XML.