I am trying to do a simple case of /author/ and get the Lift to build a Person object based on the id passed in.
Currently i have an Author snippet
class Author(item: Person) {
def render = {
val s = item match { case Full(item) => "Name"; case _ => "not found" }
" *" #> s;
}
}
object Author{
val menu = Menu.param[Person]("Author", "Author", authorId => findPersonById(authorId), person => getIdForPerson(person)) / "author"
def findPersonById(id:String) : Box[Person] = {
//if(id == "bob"){
val p = new Person()
p.name="Bobby"
p.age = 32
println("findPersonById() id = " +id)
Full(p)
//}else{
//return Empty
//}
}
def getIdForPerson(person:Person) : String = {
return "1234"
}
}
What i am attempting to do is get the code to build a boxed person object and pass it in to the Author class's constructor. In the render method i want determine if the box is full or not and proceed as appropriate.
If i change
class Author(item: Person) {
to
class Author(item: Box[Person]) {
It no longer works but if i leave it as is it is no longer valid as Full(item) is incorrect. If i remove the val s line it works (and replace the s with item.name). So how do i do this. Thanks
The Box returned from findPersonById(id:String) : Box[Person] is evaluated and if the Box is Full, the unboxed value is passed into your function. If the Box is Empty or Failure the application will present a 404 or appropriate error page instead.
You can try double boxing your return if you want to handle this error checking yourself (so that the result of this method is always a Full Box).
def findPersonById(id:String) : Box[Box[Person]] = {
if(id == "bob"){
val p = new Person()
p.name="Bobby"
p.age = 32
println("findPersonById() id = " +id)
Full(Full(p))
}else{
return Full(Empty)
}
}
and then this should work:
class Author(item: Box[Person])
Related
I have a Java program that I must implement in Scala, but I am extremely new to Scala. After reading a number of SO question & answers as well as reading through a number of Google-retrieved resources on case classes, I am still having trouble grasping how to acquire a reference to the message I received? Example code is below:
case class SpecialMessage(key: Int) {
val id: Int = Main.idNum.getAndIncrement().intValue()
def getId(): Int = {
return id
}
}
Then in another class's receive I am trying to reference that number with:
def receive() = {
case SpecialMessage(key) {
val empID = ?? getId() // Get the id stored in the Special Message
// Do stuff with empID
}
}
I cannot figure out what to put on the right sight of empID = in order to get that id. Is this really simple, or something that isn't normally done?
These are 2 ways to do what you want, pick the one that suits best
case msg: SpecialMessage => {
val empID = msg.getId() // Get the id stored in the Special Message
// Do stuff with empID
}
case msg # SpecialMessage(key) => {
val empID = msg.getId() // Get the id stored in the Special Message
// Do stuff with empID
}
Pim's answer is good.
But maybe you can modify the structure of SpecialMessage like
case class SpecialMessage(key: Int,val id: Int = Main.idNum.getAndIncrement().intValue())
so you can get id directly from pattern matching.
def receive() = {
case SpecialMessage(key, empID) {
// Do stuff with empID
}
}
I have written a lambda code that tracks login to AWS console, and send notification to user email about it.
The initial code I have written was in Java, and worked. After converting the code to Scala, I came to the following code:
class SNSHandler {
private val creds: AWSCredentials = new BasicAWSCredentials("xxx", "999/xyz12345")
private val eventType: String = "ConsoleLogin"
private val topicArn: String = "arn:aws:sns:us-east-1:1111111111:CTInterestingEvents"
def processLoginRecord(loginRecord: String, lambdaLogger: LambdaLogger) = {
val userName = JsonPath.read(loginRecord.asInstanceOf[Object], "$.userIdentity.type").asInstanceOf[String] match {
case "Root" => "Root"
case _ => JsonPath.read(loginRecord.asInstanceOf[Object], "$.userIdentity.userName")
}
val accountId = JsonPath.read(loginRecord.asInstanceOf[Object], "$.userIdentity.accountId")
new AmazonSNSClient(creds).publish(topicArn, "This is an auto notification message.\nUser " + userName +
" has logged in to AWS account id " + accountId + ".\n You are receiving this email because someone has subscribed your" +
" email address to this event.")
}
def processCloudTrailBulk(event: String, logger: LambdaLogger) = {
JsonPath.read(event.asInstanceOf[Object], "$.Records[?(#.eventName == '" + eventType + "' && #.responseElements.ConsoleLogin == 'Success')]").
asInstanceOf[java.util.List[String]].asScala.map(loginRecord => processLoginRecord(loginRecord, logger))
}
def processS3File(bucketName: String, file: String, logger: LambdaLogger) = {
Source.fromInputStream(new GZIPInputStream(new AmazonS3Client(creds).
getObject(new GetObjectRequest(bucketName, file)).getObjectContent),"UTF-8").getLines().
foreach(line => processCloudTrailBulk(line,logger))
}
def processSNSRecord(notification: SNSRecord, logger: LambdaLogger) = {
val bucketName: String = JsonPath.read(notification.getSNS.getMessage.asInstanceOf[Object], "$.s3Bucket")
logger.log("Notifications arrived.\nBucket: " + bucketName)
JsonPath.read(notification.getSNS.getMessage.asInstanceOf[Object], "$.s3ObjectKey[*]").asInstanceOf[java.util.List[String]].
asScala.map(file => processS3File(bucketName,file,logger))
}
def handleCloudTrailIncoming(event: SNSEvent, context: Context) = {
event.getRecords.asScala.map(record => processSNSRecord(record,context.getLogger))
}
}
Now, the addition of .asInstanceOf[Object] to the first param of every 'read' call wasn't there initially, however I had the famous compiler error of ambiguous reference to overloaded function, and after taking a look at: ambiguous reference to overloaded definition, from a Java library I added it, and indeed my code now compiles.
The problem is however that in runtime, the read now fails to detect the fields, and I get the following error:
Property ['s3Bucket'] not found in path $: com.jayway.jsonpath.PathNotFoundException com.jayway.jsonpath.PathNotFoundException: Property ['s3Bucket'] not found in path $ at com.jayway.jsonpath.internal.token.PropertyPathToken.evaluate(PropertyPathToken.java:41) ........
Not able to get the list of Objects when a hasMany attribute is null.
Class User {
...
List<EMail> emails
static hasMany = [emails: EMail,... ]
static mappedBy = [emails: 'customer',...]
...
}
Where Email is another Class with some String Attributes
Now i am trying to make a simple query as:
Method 1:
def users = User.findAllByEmailsIsEmpty()
This is giving Error as:
Queries of type IsEmpty are not supported by this implementation
Method 2:
def users = User.findAllByEmailsIsNull()
This is giving all the users even those have Email object associated with it.
Then I thought of trying Criteria Query (https://grails.github.io/grails-doc/latest/ref/Domain%20Classes/createCriteria.html )
Method 3:
def userCriteria = User.createCriteria()
def users = userCriteria.list(){
sizeEq('emails', 0)
}
This gives No result ( users.size() is 0 )
Method 4:
def userCriteria = User.createCriteria()
def users = userCriteria.list(){
isNull('emails')
}
This again gives all the Users even those who don't have emails.
Method 5:
def userCriteria = User.createCriteria()
def users = userCriteria.list(){
isEmpty('emails')
}
This gives the Error :
Queries of type IsEmpty are not supported by this implementation
Method 6:
def userCriteria = User.createCriteria()
def users = userCriteria.list(){
eq('emails', null)
}
This again lists down all the users.
PS: Grails is configured with Database as MongoDB.
I would use the grep method. Something like this:
nullEmailUsers = User.list().grep {
!it.emails
}
User.findAll { emails.id != null } do the job!
I am working with the Lift framework and Scala. I have a form to sign up to my application, and I want to validate all the fields in it. I have a snippet where I access my form values, and one validation class where I wrote my validation functions. The following code is what I've tried so far. In my Snippet:
if(validationClassObject.validateName(first_name)){
if(validationClassObject.validateName(last_name)){
if(validationClassObject.validateEmail(email)){
if(validationClassObject.validateUserName(name)){
// Adding values to the DB
S.redirectTo("/")
}
else{
S.notice("Invalid User Name")
}
}
else{
S.notice("Invalid Mail Id")
}
}
else{
S.notice("Invalid Last name")
}
}
else{
S.notice("Invalid First Name")
}
In the validationClass I wrote the validation code looks like:
//function for validating mail address
def validateEmail(email: String): Boolean =
"""(\w+)#([\w\.]+)""".r.unapplySeq(email).isDefined
//code for validating remaining fileds like above
This is working, but I know this is not the best way of coding this operation in Scala. How could I modify my code in a more scalable way? How can I use case classes here?
You could do:
def av[T,V](validationFunction: => Boolean, error: => T)(f: => V)={
if(!validationFunction) error
else f
}
def v[V](validationFunction: => Boolean, error: => String)(f: => V)=av(validationFunction,S.notice(error))(f)
import validationCalssObject._
v(validateName(last_name),"Invalid Last name"){v(validateName(name),"Invalid User Name"){...}}
av is a abstract method with T and V as result types for the error function and continue function f. v is the more specific function what expects a string for error and encapsulates the notice() call. we give f as the part in the curly braces v(validation, errormsg){/*todo when there is no problem*/}.
I can't do formatting in comments so I'll post a new answer.
def badName() = if ("name" == "") Some("bad name") else None
def badEmail() = if ("email" == "") Some("bad email") else None
val verifications = List[() => Option[String]](badName, badEmail)
val failed = verifications.flatMap(_())
if (failed.nonEmpty) {
// handle failed
} else {
// your custom logic here
}
if (badName) S.notice
else if (badEmail) S.notice
else if (badDay) S.notice
else { // everything OK...
// return a JsCmd or what else do you wanted here
}
An alternative solution can be written using Option and flatMap, without these all "if"-s hardcoded. If you're interested in that -- ask..
I want to copy object properties to another object in a generic way (if a property exists on target object, I copy it from the source object).
My code works fine using ExpandoMetaClass, but I don't like the solution. Are there any other ways to do this?
class User {
String name = 'Arturo'
String city = 'Madrid'
Integer age = 27
}
class AdminUser {
String name
String city
Integer age
}
def copyProperties(source, target) {
target.properties.each { key, value ->
if (source.metaClass.hasProperty(source, key) && key != 'class' && key != 'metaClass') {
target.setProperty(key, source.metaClass.getProperty(source, key))
}
}
}
def (user, adminUser) = [new User(), new AdminUser()]
assert adminUser.name == null
assert adminUser.city == null
assert adminUser.age == null
copyProperties(user, adminUser)
assert adminUser.name == 'Arturo'
assert adminUser.city == 'Madrid'
assert adminUser.age == 27
I think the best and clear way is to use InvokerHelper.setProperties method
Example:
import groovy.transform.ToString
import org.codehaus.groovy.runtime.InvokerHelper
#ToString
class User {
String name = 'Arturo'
String city = 'Madrid'
Integer age = 27
}
#ToString
class AdminUser {
String name
String city
Integer age
}
def user = new User()
def adminUser = new AdminUser()
println "before: $user $adminUser"
InvokerHelper.setProperties(adminUser, user.properties)
println "after : $user $adminUser"
Output:
before: User(Arturo, Madrid, 27) AdminUser(null, null, null)
after : User(Arturo, Madrid, 27) AdminUser(Arturo, Madrid, 27)
Note: If you want more readability you can use category
use(InvokerHelper) {
adminUser.setProperties(user.properties)
}
I think your solution is quite good and is in the right track. At least I find it quite understandable.
A more succint version of that solution could be...
def copyProperties(source, target) {
source.properties.each { key, value ->
if (target.hasProperty(key) && !(key in ['class', 'metaClass']))
target[key] = value
}
}
... but it's not fundamentally different. I'm iterating over the source properties so I can then use the values to assign to the target :). It may be less robust than your original solution though, as I think it would break if the target object defines a getAt(String) method.
If you want to get fancy, you might do something like this:
def copyProperties(source, target) {
def (sProps, tProps) = [source, target]*.properties*.keySet()
def commonProps = sProps.intersect(tProps) - ['class', 'metaClass']
commonProps.each { target[it] = source[it] }
}
Basically, it first computes the common properties between the two objects and then copies them. It also works, but I think the first one is more straightforward and easier to understand :)
Sometimes less is more.
Another way is to do:
def copyProperties( source, target ) {
[source,target]*.getClass().declaredFields*.grep { !it.synthetic }.name.with { a, b ->
a.intersect( b ).each {
target."$it" = source."$it"
}
}
}
Which gets the common properties (that are not synthetic fields), and then assigns them to the target
You could also (using this method) do something like:
def user = new User()
def propCopy( src, clazz ) {
[src.getClass(), clazz].declaredFields*.grep { !it.synthetic }.name.with { a, b ->
clazz.newInstance().with { tgt ->
a.intersect( b ).each {
tgt[ it ] = src[ it ]
}
tgt
}
}
}
def admin = propCopy( user, AdminUser )
assert admin.name == 'Arturo'
assert admin.city == 'Madrid'
assert admin.age == 27
So you pass the method an object to copy the properties from, and the class of the returned object. The method then creates a new instance of this class (assuming a no-args constructor), sets the properties and returns it.
Edit 2
Assuming these are Groovy classes, you can invoke the Map constructor and set all the common properties like so:
def propCopy( src, clazz ) {
[src.getClass(), clazz].declaredFields*.grep { !it.synthetic }.name.with { a, b ->
clazz.metaClass.invokeConstructor( a.intersect( b ).collectEntries { [ (it):src[ it ] ] } )
}
}
Spring BeanUtils.copyProperties will work even if source/target classes are different types. http://docs.spring.io/autorepo/docs/spring/3.2.3.RELEASE/javadoc-api/org/springframework/beans/BeanUtils.html