Using scala constants in constant expressions - scala

I have constants, that are made of other, smaller constants. For example
object MyConstants {
final val TABLENAME = "table_name";
final val FIELDNAME = "field_name";
final val INDEXNAME = TABLENAME + "_" + FIELDNAME + "_ix"; // this one does not want to be constant
}
I want these to be true constants because I use them in annotations.
How do I make it work? (on scala 2.11)
What I want is
interface MyConstants {
String TABLENAME = "table_name";
String FIELDNAME = "field_name";
String INDEXNAME = TABLENAME + "_" + FIELDNAME + "_ix";
}
but in scala. Scalac does not pick up constants for usage in annotations if it compiles them from java class/interface (see SI-5333) so I decided to put them in a scala object. It works for literals, and for expressions with literals, but not for expressions with other constants.
With this code:
import javax.persistence.Entity
import javax.persistence.Table
import org.hibernate.annotations.Index
object MyConstants {
final val TABLENAME = "table_name";
final val FIELDNAME = "field_name";
final val INDEXNAME = TABLENAME + "_" + FIELDNAME + "_ix";
}
#Entity
#Table(name = MyConstants.TABLENAME)
#org.hibernate.annotations.Table(
appliesTo = MyConstants.TABLENAME,
indexes = Array(new Index(name = MyConstants.INDEXNAME, columnNames = Array(MyConstants.FIELDNAME))))
class MyEntity {
}
I get a following error on line indexes = ...
annotation argument needs to be a constant; found: MyConstants.INDEXNAME
Edit:
After fiddling around with a few build configurations, I think this is actually a scala-ide specific issue. The code does indeed compile alright when I build project with gradle or sbt. I do use build tool for my actual projects, so in the end it's about having a few incomprehensible markers in the IDE - annoying, but has little to do with functionality.

I used constants in JPA with scala. This code compiles, and I used it:
FreeDays.scala
#Entity
#Table(name = "free_days")
#NamedQueries(
Array(
new NamedQuery(name = JpaQueries.IS_FREE_DAYS, query = "SELECT f FROM FreeDays f WHERE f.dateOfFreeDay = :" + JpaQueries.DATE)
)
)
class FreeDays {
def this(id: Int, name: String, dateOfFreeDay: Date) = {
this()
this.id = id
this.name = name
this.dateOfFreeDay = dateOfFreeDay
}
#Id
#GeneratedValue
var id: Long = _
var name: String = _
#Column(name = "date_of_free_day")
#Temporal(TemporalType.DATE)
var dateOfFreeDay: Date = _
}
JpaQueries.scala
object JpaQueries extends JpaQueries
sealed trait JpaQueries {
final val IS_FREE_DAYS = "IS_FREE_DAYS"
final val DATE = "date"
}

Related

Fetch table size from dynamodb using scala

Hi I am using the following code to fetch various things from DynamoDB using Scala.
I am stuck at fetching the table description.
I get the following error when I build my project:
constructor DescribeTableRequest in class DescribeTableRequest cannot be accessed in class dynDBMetadata
val tableDescription = ddbClient.describeTable(new DescribeTableRequest("Music"))
package dynDBFetchAPIs
import software.amazon.awssdk.auth.credentials.{AwsBasicCredentials, StaticCredentialsProvider}
import software.amazon.awssdk.http.apache.ApacheHttpClient
import software.amazon.awssdk.regions.Region
import software.amazon.awssdk.services.dynamodb.DynamoDbClient
import software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest
class dynDBMetadata {
def dynDBMetadataInit(): Unit = {
regionDetails()
}
def regionDetails(): Unit = {
val ddbClient = getDynDBClient()
val region = Region.US_EAST_1
var tableCount: Int = 0
var tableSize: Map[String, Int] = null
var regionSize: Int = 0
val tableList = ddbClient.listTables().tableNames()
val tableIterator = tableList.iterator()
while (tableIterator.hasNext) {
tableCount = tableCount + 1
tableIterator.next()
}
val descTabReq = new DescribeTableRequest("Music")
val tableDescription = ddbClient.describeTable(descTabReq)
println(tableDescription)
println("Region of AWS DynamoDB: " + region)
println("List of DynamoDB Tables: " + tableList)
println("Count of DynamoDB Tables: " + tableCount)
}
private def getDynDBClient(): DynamoDbClient = {
var awsBasicCredentials: AwsBasicCredentials = null
var dynamoDbClient: DynamoDbClient = null
try {
val accessKey = "****************************"
val secretKey = "****************************"
awsBasicCredentials = AwsBasicCredentials.create(accessKey, secretKey)
dynamoDbClient = DynamoDbClient.builder()
.region(Region.US_EAST_1)
.credentialsProvider(StaticCredentialsProvider.create(awsBasicCredentials))
.httpClient(ApacheHttpClient.builder().build())
.build();
} catch {
case e: Exception => {
e.printStackTrace()
}
}
dynamoDbClient
}
}
Why is the given constructor not accessible when I use Scala?
contents of build.sbt
name := "dynamodb"
version := "0.1"
scalaVersion := "2.11.12"
scalacOptions := Seq("-target:jvm-1.8")
libraryDependencies ++= Seq(
"software.amazon.awssdk" % "dynamodb" % "2.15.1"
)
I believe that happends because class software.amazon.awssdk.services.dynamodb.model.DescribeTableRequest doesn't have a primary constructor.
You should create with the builder, like this
val tableRequest = DescribeTableRequest.builder
.tableName(tableName)
.build
com.amazonaws.services.dynamodbv2.model.DescribeTableRequest instead, does have a primary constructor. So, maybe you've just included a wrong dependency.

Scala 2.11.8, OS:Windows 7, Java: JDK1.8

I am creating a Companion Objects, How do i traverse these objects?, i have written but not working, error thrown
Please help here
scala> :paste
object Network {
class Member(val name: String) {
var strName = name
val contacts = new collection.mutable.ArrayBuffer[Member]
println(" name -->" + strName)
}
}
class Network {
private val members = new collection.mutable.ArrayBuffer[Network.Member]
def join(name: String) = {
val m = new Network.Member(name)
members += m
m
}
}
val chatter = new Network
val myFace = new Network
val fred = chatter.join("Fred")
val wilma = chatter.join("Wilma")
fred.contacts += wilma // OK
val barney = myFace.join("Barney") // Has type myFace.Member
fred.contacts += barney // allowed
How do i traverse these objects?, i have written but not working, error thrown
for (a<- fred.contacts){
var Network.Member m = a
println("m -->" + m.strName)
//println("m -->" + a)
}
The declaration of m variable is not correct.
var m:Network.Member = a
That's the correct way to declare a variable in Scala. Or you can just ignore the type and let Scala interpret it.
var m = a

Scala class: avoid parameters while creating new instance

Suppose I have 2 files.
myMainApplication.scala
printInfos.scala
Briefly myMainApplication.scala contains
val name = "blah"
val age= 45
Briefly my class myMainApplication.scala should print out the name and the age by creating a new printInfos instance. However I should not add any parameters while creating the instance.
What I would like to AVOID:
Inside printInfos.scala
class printInfos(val myName: String,
val myAge: Int
val myLoc: String
val myNPP: Double
val myCountry: String
val myProvice: String
val myNPAP: String) {
def printInfos() = {
println("Your method printInfos print out" + myName + myAge + myLoc + myNPP + myCountry + myProvice + myNPAP)
}
}
Inside myMainApplication.scala
val name = "blah"
val age= 45
val loc = "blah"
val npp = 45.5
val country = "germany"
val province = "bayern"
val npap = "blaha"
// want to avoid to enter so many params
val printInfoInstance = new printInfos(name, age, loc, npp, country, province, npap)
printInfoInstance.printInfos()
I would like to get something similar:
Inside printInfos.scala
class printInfos() {
var myName: String = 0
var myAge: Int = 0
var myLoc: String = 0
var myNPP: Double = 0
var myCountry: String = 0
var myProvice: String = 0
var myNPAP: String = 0
def printInfos() = {
println("Your method printInfos print out" + myName + myAge + myLoc + myNPP + myCountry + myProvice + myNPAP)
}
}
Inside myMainApplication.scala
// want to create new instance with no params at begining
val printInfoInstance = new printInfos()
val name = "blah"
printInfoInstance.myName() = name
val age= 45
printInfoInstance.myAge() = age
val loc = "blah"
printInfoInstance.myLoc() = loc
val npp = 45.5
printInfoInstance.myNPP() = npp
val country = "germany"
printInfoInstance.myCountry() = country
val province = "bayern"
printInfoInstance.myProvice() = province
val npap = "blaha"
printInfoInstance.myNPAP() = npap
printInfoInstance.printInfos
Looking for improvements
Would it be possible to get something similar to the second proposal but avoiding to use var ? However, the final aim is still to avoid adding a lot of parameters when creating a new intance.
I'd suggest you use scala's case classes for this. It provides a copy method that allows you to create a new instance with the changed parameters. This keeps everything immutable. Note that you don't have to update all of the parameters - you could just do one at a time.
case class printInfos(myName: String = "",
myAge: Int = 0,
myLoc: String = "",
myNPP: Double = 0,
myCountry: String = "",
myProvince: String = "",
myNPAP: String = "") {
def printInfos() = {
println("Your method printInfos print out" + myName + myAge + myLoc + myNPP + myCountry + myProvince + myNPAP)
}
}
val printInfoInstance = new printInfos()
val name = "blah"
val age= 45
val loc = "blah"
val npp = 45.5
val country = "germany"
val province = "bayern"
val npap = "blaha"
val newInstance = printInfoInstance.copy(
myName = name,
myAge = age,
myLoc = loc,
myNPP = npp,
myCountry = country,
myProvince = province,
myNPAP = npap
)
newInstance.printInfos()
In addition to what #longshorej has mentioned, provided you have a case class defined. you can instantiate without the new keyword:
printInfos("name","age","loc","npp","country","province","npap") would create a new instance.
For the printing part I'd suggest overriding toString so that it aligns well with standard nomenclature.
It is a benefit of the type system to be able to require all the parameters needed to create a valid instance of a class.
If you want to avoid the verbosity of passing all the parameters every time, you can provide default values for them (only a good idea if they are truly optional, as you really want to avoid invalid intermediate states).
// assuming it doesn't make sense to instantiate without
// a few required parameters
case class InfoPrinter (
name: String, // required
age: Int, // required
loc: String = "",
NPP: Double = 0,
country: String = "",
province: String = "",
NPAP: String = ""
) {
def printInfos =
println(s"Your method printInfos print out $name $age $loc $NPP $country $province $NPAP")
}
You can then use it like this:
// named params or positionally
InfoPrinter("blah", 45, country="germany", province="bayern").printInfos
Any parameters with default values can be omitted.

Ebean not persisting foreign keys

I have a simple Entity class like;
case class Place(var name: String) extends Model with GeoLocPoint with HasGeoLoc with ContainsTime with HasId {
var number: String = _ // Building number on the street.
var placeGroupId: Long = _
var chainId: Long = _
#OneToOne
#JoinColumn(name = "logo_id")
var logo: Image = _
#OneToOne
#JoinColumn(name = "cover_id")
var cover: Image = _
...
}
And the image class is;
package models.images
import javax.persistence.Entity
import models.HasId
import models.places.placegroups.places.{Place, LinkedToPlace}
import play.api.libs.json._
import play.db.ebean.Model
import play.db.ebean.Model.Finder
/**
* Created by asheshambasta on 31/12/14.
*/
#Entity
case class Image(
filePath: String,
src: String,
format: String,
role: String // C: cover, L: logo, G: gallery
) extends Model with HasId with LinkedToPlace {
var caption: String = _
}
Now when a place is created, I'm attaching a default image to it;
newPlace.save
val imgDir = Play.current.configuration.getString("static.dir").getOrElse("/tmp")
val imgUrl = Play.current.configuration.getString("static.url.img").getOrElse("/static/img")
val imgType = Play.current.configuration.getString("img.default.type").getOrElse("image/jpeg")
val coverFile = Play.current.configuration.getString("img.default.cover.file").getOrElse("default-cover.jpg")
val logoFile = Play.current.configuration.getString("img.default.cover.file").getOrElse("default-cover.jpg")
val cover = new Image(imgDir + "/" + coverFile, imgUrl + "/" + coverFile, imgType, "C")
cover.place = newPlace
cover.save
val logo = new Image(imgDir + "/" + logoFile, imgUrl + "/" + logoFile, imgType, "L")
logo.place = newPlace
logo.save
newPlace.cover = cover
newPlace.logo = logo
newPlace.update
But then every time, I see that the images get persisted correctly with the right place_id but the place logo and the cover don't. They stay null.
This seems straight forward, and yet it doesn't work. Does anyone have any pointers to why?
There are some innacuracies in provided code. There is
logo.place = newPlace
but there is no place field in Image class.
There is also place_id column mentioned but I cannot see it in the code. But there are logo_id and cover_id columns. When you do one-to-one relation you should add join-column only on one side of this relation. So it should be only logo_id and cover_id columns on Place table. Adding only place_id column on Image table would not work because there would be two rows in Image table with the same place_id and this would be impossible to distinguish which should be mapped to logo field and which to cover field.
I made some corrections and simplifications to make this code compile and work.
Place.scala:
#Entity
class Place( var aId: Int, var aNumber: String) extends Model{
#Id
val id:Int=aId
#Column(name="number")
var number: String = aNumber
#OneToOne
#JoinColumn (name = "logo_id")
var logo: Image = _
#OneToOne
#JoinColumn(name = "cover_id")
var cover: Image = _
}
Image.class:
#Entity
#Table(name = "image")
class Image(var aId: Int, var aCaption: String) extends Model {
#Id
val id:Int=aId
#Column(name="caption")
var caption: String = aCaption
}
test method:
"EbeanTest" should {
"placeTest" in new WithApplication {
val newPlace = new Place(1, "aaa")
newPlace.save
val logo: Image = new Image(1, "111");
logo.save
val cover: Image = new Image(2, "222");
cover.save
newPlace.logo=logo
newPlace.cover=cover
newPlace.update
val cList = Ebean.find(classOf[Place]).findList()
for (
element <- cList
) println(element.id+" "+element.number+" "+element.logo.id+" "+element.cover.id)
}
}

Is there an better alternative to implement Builder Pattern in Scala?

I have to create an instance of class BenchmarkOption based on the command line arguments. I certainly use pojo style, but this is not immutable. So I use Builder Pattern of Java style. Here is the class I implement :
object CommandLineHelper {
//TODO: use configuration file ?
val MILLI_SEC_SEPERATORS = 0 + "," + Int.MaxValue
val SBE_ID = "SBETEST5";
val SBE_PSW = "GZ#API53";
val NUM_OF_REQUESTS = 1
val NUM_OF_WORKERS = 1
val PAUSE_IN_MILlI_SECOND = 1L;
}
class BenchmarkOption private {
import com.ggd543.mulerestletdemo.{CommandLineHelper => CLH}
private var _msSeperators = CommandLineHelper.MILLI_SEC_SEPERATORS
def msSeperators = _msSeperators
private var _nOfReq = CLH.NUM_OF_REQUESTS
def nOfReq = _nOfReq
private var _sbeId = CLH.SBE_ID
def sbeId = _sbeId
private var _sbePsw = CLH.SBE_PSW
def sbePsw = _sbePsw
private var _pauseInMilliSec = CLH.PAUSE_IN_MILlI_SECOND;
def pauseInMillSec = _pauseInMilliSec
private var _dataFile = new File("./data.csv")
def dataFile = _dataFile
// may be too many fields
}
object BenchmarkOption {
def newBuilder() = new Builder
class Builder {
private val bmo = new BenchmarkOption
def buildBenchmarkOption = bmo;
def msSeperators_=(s: String) = bmo._msSeperators = s
def msSeperators = bmo._msSeperators
def nOfReq_=(n: Int ) = bmo._nOfReq = n
def nOfReq = bmo._nOfReq
def sbeId_=(s: String) = bmo._sbeId = s
def sbeId = bmo._sbeId
def sbePsw_=(s: String ) = bmo._sbePsw = s
def sbePsw = bmo._sbePsw
def pauseInMilliSec_=(milliSec: Long) = bmo._pauseInMilliSec = milliSec
def pauseInMilliSec = bmo._pauseInMilliSec
def dataFile_=(file: File) = bmo._dataFile = file
def dataFile = bmo._dataFile
}
}
As you can see that the code is lengthy and not good at reading. I think there is an alternative to rewrite it . Any suggestion ?
The Builder Pattern is built into Scala. Just use named constructor arguments and default values whenever possible. If there are too many arguments, then rethink your design. I bet there are plenty opportunities to group them somehow into proper data structures, thus reducing the number of constructor arguments.
I don't see why you can' just use constructor arguments - are all parameters not known from the start?
How about this ?
class BenchmarkOption private {
protected val instance = new {
var msSeperators = CommandLineHelper.MILLI_SEC_SEPERATORS
var nOfReq = CLH.NUM_OF_REQUESTS
var sbeId = CLH.SBE_ID
var sbePsw = CLH.SBE_PSW
var pauseInMilliSec = CLH.PAUSE_IN_MILlI_SECOND;
var dataFile = new File("./data.csv" )
def buildInstance() = BenchmarkOption.this;
}
def msSeperators = instance.msSeperators
def nOfReq = instance.nOfReq
def sbeId = instance.sbeId
def sbePsw = instance.sbePsw
def pauseInMilliSec = instance.pauseInMilliSec
def dataFile = instance.dataFile
}
object BenchmarkOption {
def newBuilder() = new BenchmarkOption{}.instance
}