I have scala class like:
#Entity("users")
class User(#Required val cid: String, val isAdmin: Boolean = false, #Required val dateJoined: Date = new Date() ) {
#Id var id: ObjectId = _
#Reference
val foos = new ArrayList[Foo]
}
If it was a Java class I would simply put implements java.io.Serializable but this does not work in scala. Also is foos as declared above is private or public?
How do I use a #serializable scala object?
foos is public unless marked otherwise
scala 2.9.x also have an interface named Serializable, you may extends or mixin this. before 2.9.x the #serializable is the only choice.
You can add Serialized annotation on your Scala Class (at JPA Entity for example):
Because Serializable is a trait, you can mix it into a class, even if
your class already extends another class:
#SerialVersionUID(114L)
class Employee extends Person with Serializable ...
Se more details at this link:
https://www.safaribooksonline.com/library/view/scala-cookbook/9781449340292/ch12s08.html
An example of my Entity (JPA) class writed in scala, using Serialized properties:
import javax.persistence._
import scala.beans.BeanProperty
import java.util.Date
#SerialVersionUID(1234110L)
#Entity
#Table(name = "sport_token")
class Token() extends Serializable {
#Id
#SequenceGenerator(name="SPORT_TOKEN_SEQ",catalog="ESPORTES" , sequenceName="SPORT_TOKEN_SEQ", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE , generator="SPORT_TOKEN_SEQ")
#BeanProperty
var id: Int = _
#BeanProperty
#Column(name="token")
var token: String = _
#BeanProperty
#Column(name="active")
var active: Int = _
}
Related
Scala does not get first class support as Kotlin in Spring.
I tried to create a Spring Boot API application with Scala.
Spring Boot 2.2.0.M5
Spring Data JPA
H2
Scala 2.13
I created a JPA Entity with case class like:
#Entity
case class Post(#BeanProperty title: String, #BeanProperty content: String) {
def this() {
this(null, null)
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#BeanProperty
var id: Long = _
#BeanProperty
val createdOn: LocalDateTime = LocalDateTime.now()
override def toString: String = s"Post[id:$id, title:$title, content:$content, createdOn:$createdOn]"
}
And create a Repository using trait, it works.
trait PostRepository extends JpaRepository[Post, Long]
I want to try bean validation.
class PostForm {
#NotNull
#NotEmpty
#BeanProperty var title: String = _
#BeanProperty var content: String = _
}
And in the controller, create a POST method like:
#PostMapping
def save(#RequestBody #Valid form: PostForm, errors: BindingResult) = errors.hasErrors match {
case true => {
badRequest().build()
}
case _ => {
val data = Post(title = form.title, content = form.content)
val saved = posts.save(data)
created(ServletUriComponentsBuilder.fromCurrentContextPath().path("/{id}").buildAndExpand(saved.id).toUri).build()
}
}
It works.
But the model classes are little tedious. I am trying to use a case class like the following:
case class PostForm(#NotNull #NotEmpty #BeanProperty title: String, #BeanProperty content: String)
The validation does not work.
When we are modeling for JPA etc, case class or generic class is better?
Why we can not apply the Bean Validation annotations as Kotlin data clase in the case class?
Update: Got this work like:
case class PostForm(#(NotNull#field) #(NotEmpty#field) #BeanProperty title: String, #BeanProperty content: String)
The source codes is hosted on my Github.
Case class fields are considered as vals by default, which means you can't set a new value to them. #BeanProperty, however, is to automatically generate field setters and getters.
You may try adding var keywords to the fields explicitly.
case class PostForm(
#NotNull #NotEmpty #BeanProperty var title: String,
#BeanProperty var content: String
)
What I want is to have two user types that inherit from one user super class. When I'm authenticating a user through username/password I don't care who they are at that point. However once they start making requests once logged in it will become important then.
I don't know what I should be using for the inheritance type and the repositories in kotlin for this.
#MappedSuperClass
open class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
val Id: Long = 0
val username:String = ""
val password:String = ""
}
type1
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
data class Type1(
val property1: String) : User
{
val property2: String = ""
}
type2
#Entity
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
data class Type2(
val property1: String) : User
{
val property2: String = ""
}
What I'd like to have is a user repository to be able to look at user name and password, and then repositories for the other two to get the specific properties of each. I tried
#Repository
interface UserRepository: JpaRepository<User, Long> {
fun getUserByUsername(username: String)
}
and then
#Repository
interface Type1Repository: UserRepository<Type1, Long>
but it wouldn't accept the <> in the type 1 repository.
I haven't found a good resource talking about this for kotlin yet. If you know of one please pass it along. Thanks.
Like shown in here: https://ideone.com/JmqsDn you are just missing the types in your intermediate interface, ie.:
interface UserRepository<User, Long>: JpaRepository<User, Long> {
fun getUserByUsername(username: String)
}
Side note: kotlin 1.1+ is required for data classes to inherit from other classes.
In Scala, I am trying to convert from Java POJO class to Scala Case class. Please below find the details:
//Java POJO Response Class
#JsonIgnoreProperties(ignoreUnknown = true)
public class IncidentResponse {
private String issueType;
private List<OrderDetailResponse> orderDetails;
//GETTER and SETTERs}
#JsonIgnoreProperties(ignoreUnknown = true)
public class OrderDetailResponse {
private String orderId;
private String orderItemId;
//GETTER and SETTERs
public List<OrderDetailResponse> getOrderDetails() {return this.orderDetails;}}
//Scala Case Class
#JsonNaming(classOf[SnakeCaseStrategy])
#JsonIgnoreProperties(ignoreUnknown = true)
case class IncidentDetails(issueType: String,
orderDetails: List[OrderDetailResponse])
//OrderDetailResponse is from the Scala Case Class
#JsonNaming(classOf[SnakeCaseStrategy])
#JsonIgnoreProperties(ignoreUnknown = true)
case class OrderDetailResponse(orderId:String,
orderItemId:String)
I have tried the below ways to convert the data in SnakeCase -
Variable "data" contains the IncidentResponse of JAVA POJO Class
Using asInstanceof List[Map] and then using Object Mapper convert it to the OrderDetailResponse
val orderDetails = data.getOrderDetails.asInstanceOf[List[Map[String, Any]]].map(p => (mapper.convertValue(p, typeReference[OrderDetailResponse](tTag)).asInstanceOf[OrderDetailResponse].get))
IncidentDetails(data.getIssueType,orderDetails)
Got the error as - java.util.ArrayList cannot be cast to scala.collection.immutable.List
Tried to convert List[Map[Object,Object]]:
val scalaList =data.getOrderDetails.asScala.toList.asInstanceOf[List[Map[Object,Object]]]
IncidentDetails(data.getIssueType,
scalaList.asInstanceOf[List[OrderDetailResponse]])
Didn't get any error with this, however it was not converted to SnakeCase of OrderDetailResponse but issueType was converted to SnakeCase
If i assign values individually from the POJO class then it will work, if I have many fields then it will leads to many lines of code so how to convert to SnakeCase of Scala case class from Java POJO class.
IncidentDetails(data.getIssueType,
data.getOrderDetails.asScala.head.map(orderResp =>
OrderDetailResponse(orderResp.getOrderId,orderResp.getOrderItemId)
)
Trying to get values of all fields of child from parent class like this:
for (field <- this.getClass.getDeclaredFields) {
Logger.debug(field.getName)
field.get(this)
}
and got error
Exception: Class models.Model$$anonfun$4 can not access a member of
class models.Good with modifiers "private"
at line
field.get(this)
In Good class I don't have private fields:
class Good(id: Option[String]) extends Model[realGood](id){
lazy val title: String = this.load[String](realObject.get.title)
lazy val cost: Double = this.load[Double](realObject.get.cost)
}
What's wrong with this code?
As hinted in the comments, Scala's conversion to java bytecode isn't always straightforward (though it's usually pretty predictable, once you get the hang of it). In particular, public fields in Scala compile to a private field with a public getter in java bytecode:
fukaeri:~ dlwh$ cat zzz.scala
class Good(id: Option[String]) {
lazy val title: String = ???
lazy val cost: Double = ???
}
fukaeri:~ dlwh$ scalac zzz.scala
fukaeri:~ dlwh$ javap -private Good
Compiled from "zzz.scala"
public class Good {
private java.lang.String title;
private double cost;
private volatile byte bitmap$0;
private java.lang.String title$lzycompute();
private double cost$lzycompute();
public java.lang.String title();
public double cost();
public Good(scala.Option<java.lang.String>);
}
You can see that Good has private fields for each of your declared public fields, in addition to public getters. Because the fields are lazy val, they also have computation methods for initialization, and there's a bitmap$0 field to ensure that the lazy vals are initialized only once.
In your loop, you can use field.setAccessible(true) to fix your exception.
I'm having trouble using Amazon's DynamoDBMapper in Scala code. The main sticking point is getting the JVM to recognize #DynamoDBHashkey when it is used in a case class, like:
case class MyCoolCaseClass(#DynamoDBHashKey(attributeName = "my_id") myId: String) {}
Any pointers from someone who has integrated this client library into a Scala project? (I'm hoping to not simply fallback to the low-level API, though that may be a decent decision once exhausting my options with the Mapper).
I had to do this:
import annotation.meta.beanGetter
import beans.BeanProperty
import com.amazonaws.services.dynamodbv2.datamodeling._
#DynamoDBTable(tableName="DEMOTAB")
case class DemoItem( // it's a case class for the free stuff, but can be ordinary class
#(DynamoDBHashKey #beanGetter) // would not work without meta annotation
#BeanProperty var id:String, // must be var or mapper can't instantiate one
#BeanProperty var number:Integer
) {
def this() = this(null, null) // needed by DynamoDB Mapper to instantiate
}
The DynamoDB mapper uses reflection to find the getters and setters. The SDK assumes Java-style conventions, i.e. that your getters and setters start with "get" or "is", and setters start with "set". You can see the reflection code on github.
I've been able to get it working, but it feels just like writing Java :(
#DynamoDBTable(tableName = "awesome_table")
class TheBestClass {
private var id : Integer = _
#DynamoDBHashKey
def getId() = id
def setId(_id: Integer) = id = _id
}
This works for me, including the boolean
#DynamoDBTable(tableName = "User")
case class User(
#(DynamoDBHashKey #field)
#(DynamoDBAutoGeneratedKey #field)
#BeanProperty var id: String,
#(DynamoDBAttribute #field)
#BeanProperty var firstName: String,
#(DynamoDBAttribute #field)
#BeanProperty var lastName: String,
#(DynamoDBAttribute #field)
#BeanProperty var active: Boolean
)
{
def this() = this(null, null, null, false)
}