This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 17.6, “How to create JavaBeans in Scala (to interact with Java libraries).”
Problem
In your Scala code, you need to interact with a Java class or library that only accepts classes that conform to the JavaBean specification.
Solution
Use the @BeanProperty
annotation on your fields, also making sure you declare each field as a var
.
The @BeanProperty
annotation can be used on fields in a Scala class constructor:
import scala.reflect.BeanProperty class Person(@BeanProperty var firstName: String, @BeanProperty var lastName: String) { override def toString = s"Person: $firstName $lastName" }
It can also be used on the fields in a Scala class:
import scala.reflect.BeanProperty class EmailAccount { @BeanProperty var username: String = "" @BeanProperty var password: String = "" override def toString = s"Email Account: ($username, $password)" }
To demonstrate this, create an SBT project, then save the following code to a file named Test.scala in the root directory of the project:
package foo import scala.reflect.BeanProperty class Person(@BeanProperty var firstName: String, @BeanProperty var lastName: String) { } class EmailAccount { @BeanProperty var username: String = "" @BeanProperty var password: String = "" }
This code shows how to use the @BeanProperty annotation on class constructor parameters, as well as the fields in a class.
Next, create a directory named src/main/java/foo, and save the following Java code in a file named Main.java in that directory:
package foo; public class Main { public static void main(String[] args) { // create instances Person p = new Person("Regina", "Goode"); EmailAccount acct = new EmailAccount(); // demonstrate 'setter' methods acct.setUsername("regina"); acct.setPassword("secret"); // demonstrate 'getter' methods System.out.println(p.getFirstName()); System.out.println(p.getLastName()); System.out.println(acct.getUsername()); System.out.println(acct.getPassword()); } }
This Java code demonstrates how to create instances of the Scala Person
and EmailAccount
classes, and access the JavaBean methods of those classes. When the code is run with sbt run
, you’ll see the following output, showing that all the getter and setter methods work:
$ sbt run [info] Running foo.Main Regina Goode regina secret
Discussion
You can see how the @BeanProperty
annotation works by compiling a simple class and then disassembling it. First, save these contents to a file named Person.scala:
import scala.reflect.BeanProperty class Person(@BeanProperty var name: String, @BeanProperty var age: Int) { }
Then compile the class:
$ scalac Person.scala
After it’s compiled, disassemble it with the javap
command:
$ javap Person Compiled from "Person.scala" public class Person extends java.lang.Object implements scala.ScalaObject{ public java.lang.String name(); public void name_$eq(java.lang.String); public void setName(java.lang.String); public int age(); public void age_$eq(int); public void setAge(int); public int getAge(); public java.lang.String getName(); public Person(java.lang.String, int); }
As you can see from the disassembled code, the methods getName
, setName
, getAge
, and setAge
have all been generated because of the @BeanProperty
annotation.
Note that if you declare your fields as type val
, the “setter” methods (setName
, setAge
) won’t be generated:
Compiled from "Person.scala" public class Person extends java.lang.Object implements scala.ScalaObject{ public java.lang.String name(); public int age(); public int getAge(); public java.lang.String getName(); public Person(java.lang.String, int); }
Without these methods, your class will not follow the JavaBean specification.
As a final example, if the @BeanProperty
annotation is removed from all fields, you’re left with this code:
class Person(var firstName: String, var lastName: String)
When you compile this code with scalac
and then disassemble it with javap
, you’ll see that no getter or setter methods are generated (except for those that follow the Scala convention):
Compiled from "Person.scala" public class Person extends java.lang.Object{ public java.lang.String firstName(); public void firstName_$eq(java.lang.String); public java.lang.String lastName(); public void lastName_$eq(java.lang.String); public Person(java.lang.String, java.lang.String); }
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
See Also
- My tutorial about using the Java SnakeYaml library in Scala shows more examples of the
@BeanProperty
annotation.