I have the following POST body examples:
{ "Id": "123abxy"}
{ "customUrl": "http://www.whiskey.com","Id": "123abxy"}
{ "size": "88", "customUrl": "http://www.whiskey.com","Id": "123abxy"}
And the following endpoint:
case class aType(
customUrl: Option[String],
Id:Option[String],
size:Option[String]
)
#ResponseBody
def addCompany(
#RequestBody a: aType,
#ModelAttribute("action-context") actionContext: ActionContext
): DeferredResult[Created] = Action[Created]
{
val customUrl = {
a.customUrl
}
val size = {
if (a.size == None) {None}
else Option(a.size.get.toLong)
}
val Id = {
a.Id
}
val handle = register(
customUrl,
Id,
size
).run()
}.runForSpring[Nothing](executors, actionContext)
Also:
def register(
customUrl: Option[String],
Id: Option[String],
size: Option[Long]
)
Given the above, I would like to know the correct way to handle the case where size and customUrl are not passed into the POST Body.
In this case, since size can be either a value (Long) or null and customUrl can be either a String or null, I would assume the proper data type to handle this would be Option[String] and Option[Long] for customUrl and size, respectively.
My question is how should I change the if-else clauses to handle the aforementioned scenarios for null or String/Long, so that I can pass valid variables into the register(..) function ?
Cheers,
If the register function receives size and customURL as Options, what's the problem?
I would do something like this:
#ResponseBody
def addCompany(
#RequestBody a: aType,
#ModelAttribute("action-context") actionContext: ActionContext
): DeferredResult[Created] = Action[Created]
{
val handle = register(a.customUrl,a.id,a.size).run()
}.runForSpring[Nothing](executors, actionContext)
If there is a requirement to return None if size is not defined then:
#ResponseBody
def addCompany(
#RequestBody a: aType,
#ModelAttribute("action-context") actionContext: ActionContext
): DeferredResult[Created] = Action[Created]
{
val sizeOpt = a.size
val handle =sizeOpt.map { size =>
register(a.customUrl,a.id,Some(size)).run()
}
}.runForSpring[Nothing](executors, actionContext)
But even better, would be your register function not to expect Options, and deal only with the primitive types. Then you would only need to map the 3 optional values (I recommend to use for comprehension):
for {
size <- a.size
url <- a.customUrl
id <- a.id
} yield register(url, id, size).run()
with register defined as:
def register(
customUrl:String,
Id: String,
size: Long
)
Related
I have a parameter
case class Envelope(subject: Option[String]) {
}
and I want to apply a require function only if subject is non null.
Something like below:
require(StringUtils.isNotBlank(subject))
You can try this also:
case class Envelope(subject: Option[String])
def check(en: Envelope): Boolean = {
require(en.subject.isDefined)
true
}
It will be finer and you don't have any need to import StringUtils.
For fetching the value from Option you should go for the getorElse. Here we can define the default value for the variable. Ex:
def check(str: Option[String]): String = {
str.getOrElse("")
}
scala> check(None)
res1: String = ""
scala> check(Some("Test"))
res2: String = Test
Only get will throw the exception when it will get None. Ex:
def check(str: Option[String]): String = {
str.get
}
scala> check(Some("Test"))
res2: String = Test
scala> check(None)
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:347)
at scala.None$.get(Option.scala:345)
at check(<console>:24)
... 48 elided
I think you can go that way:
subject.map(s => if(StringUtils.isNotBlank(s)) require(s) else s)
Options should, from a practical perspective, almost never be null in Scala (I'd argue never, but there are all sorts of compromises and exceptions, especially when working with Java dependencies where null checks are more common-place).
With some pre-processing and pattern-matching, you may find this approach acceptable:
// When working with `Option`s, naming convention usually is "[name_of_var]Opt"
case class Envelope( subjectOpt: Option[String] ) {
// Utility to check whether or not this `Envelope` has a subject
def hasSubject: Boolean = subjectOpt.isDefined
// Get the subject or throw an exception if it does not have one (None)
def getSubject: String = {
subjectOpt match {
case None => throw Exception( "Envelope has no subject!" )
case Some( subject ) => subject
}
}
}
object Envelope {
// Utility to create an `Envelope` with no subject
def apply(): Envelope = Envelope(None)
// Utility to do a bit of pre-processing, checking for `null` or empty strings
def apply( subject: String ): Envelope = {
if ( subject == null || subject.isEmpty ) Envelope()
else Envelope( Some( subject ) )
}
}
val nullString: String = null
// Example usages (will have no subject):
val envelopeWithNoSubject: Envelope = Envelope()
val envelopeWithEmptySubject: Envelope = Envelope( "" )
val envelopeWithNullSubject: Envelope = Envelope( nullString )
// envelopeWithNoSubject, ...EmptySubject, and ...NullSubject all return:
... .hasSubject // False
... .getSubject // Exception: Envelope has no subject!
// Example use with subject
val envelopeWithSubject: Envelope = Envelope( "Scala" )
envelopeWithSubject.hasSubject// True
envelopeWithSubject.getSubject // "Scala"
You should be changing the require function call to the following
require(StringUtils.isBlank(subject.get))
.get method returns the string that the subject Option carries.
My use case has case classes something like
case class Address(name:String,pincode:String){
override def toString =name +"=" +pincode
}
case class Department(name:String){
override def toString =name
}
case class emp(address:Address,department:Department)
I want to create a DSL like below.Can anyone share the links about how to create a DSL and any suggestions to achieve the below.
emp.withAddress("abc","12222").withDepartment("HR")
Update:
Actual use case class may have more fields close to 20. I want to avoid redudancy of code
I created a DSL using reflection so that we don't need to add every field to it.
Disclamer: This DSL is extremely weakly typed and I did it just for fun. I don't really think this is a good approach in Scala.
scala> create an Employee where "homeAddress" is Address("a", "b") and "department" is Department("c") and that_s it
res0: Employee = Employee(a=b,null,c)
scala> create an Employee where "workAddress" is Address("w", "x") and "homeAddress" is Address("y", "z") and that_s it
res1: Employee = Employee(y=z,w=x,null)
scala> create a Customer where "address" is Address("a", "b") and "age" is 900 and that_s it
res0: Customer = Customer(a=b,900)
The last example is the equivalent of writing:
create.a(Customer).where("address").is(Address("a", "b")).and("age").is(900).and(that_s).it
A way of writing DSLs in Scala and avoid parentheses and the dot is by following this pattern:
object.method(parameter).method(parameter)...
Here is the source:
// DSL
object create {
def an(t: Employee.type) = new ModelDSL(Employee(null, null, null))
def a(t: Customer.type) = new ModelDSL(Customer(null, 0))
}
object that_s
class ModelDSL[T](model: T) {
def where(field: String): ValueDSL[ModelDSL2[T], Any] = new ValueDSL(value => {
val f = model.getClass.getDeclaredField(field)
f.setAccessible(true)
f.set(model, value)
new ModelDSL2[T](model)
})
def and(t: that_s.type) = new { def it = model }
}
class ModelDSL2[T](model: T) {
def and(field: String) = new ModelDSL(model).where(field)
def and(t: that_s.type) = new { def it = model }
}
class ValueDSL[T, V](callback: V => T) {
def is(value: V): T = callback(value)
}
// Models
case class Employee(homeAddress: Address, workAddress: Address, department: Department)
case class Customer(address: Address, age: Int)
case class Address(name: String, pincode: String) {
override def toString = name + "=" + pincode
}
case class Department(name: String) {
override def toString = name
}
I really don't think you need the builder pattern in Scala. Just give your case class reasonable defaults and use the copy method.
i.e.:
employee.copy(address = Address("abc","12222"),
department = Department("HR"))
You could also use an immutable builder:
case class EmployeeBuilder(address:Address = Address("", ""),department:Department = Department("")) {
def build = emp(address, department)
def withAddress(address: Address) = copy(address = address)
def withDepartment(department: Department) = copy(department = department)
}
object EmployeeBuilder {
def withAddress(address: Address) = EmployeeBuilder().copy(address = address)
def withDepartment(department: Department) = EmployeeBuilder().copy(department = department)
}
You could do
object emp {
def builder = new Builder(None, None)
case class Builder(address: Option[Address], department: Option[Department]) {
def withDepartment(name:String) = {
val dept = Department(name)
this.copy(department = Some(dept))
}
def withAddress(name:String, pincode:String) = {
val addr = Address(name, pincode)
this.copy(address = Some(addr))
}
def build = (address, department) match {
case (Some(a), Some(d)) => new emp(a, d)
case (None, _) => throw new IllegalStateException("Address not provided")
case _ => throw new IllegalStateException("Department not provided")
}
}
}
and use it as emp.builder.withAddress("abc","12222").withDepartment("HR").build().
You don't need optional fields, copy, or the builder pattern (exactly), if you are willing to have the build always take the arguments in a particular order:
case class emp(address:Address,department:Department, id: Long)
object emp {
def withAddress(name: String, pincode: String): WithDepartment =
new WithDepartment(Address(name, pincode))
final class WithDepartment(private val address: Address)
extends AnyVal {
def withDepartment(name: String): WithId =
new WithId(address, Department(name))
}
final class WithId(address: Address, department: Department) {
def withId(id: Long): emp = emp(address, department, id)
}
}
emp.withAddress("abc","12222").withDepartment("HR").withId(1)
The idea here is that each emp parameter gets its own class which provides a method to get you to the next class, until the final one gives you an emp object. It's like currying but at the type level. As you can see I've added an extra parameter just as an example of how to extend the pattern past the first two parameters.
The nice thing about this approach is that, even if you're part-way through the build, the type you have so far will guide you to the next step. So if you have a WithDepartment so far, you know that the next argument you need to supply is a department name.
If you want to avoid modifying the origin classes you can use implicit class, e.g.
implicit class EmpExtensions(emp: emp) {
def withAddress(name: String, pincode: String) {
//code omitted
}
// code omitted
}
then import EmpExtensions wherever you need these methods
I'm new to the concept of using the Option type but I've tried to use it multiple places in this class to avoid these errors.
The following class is used to store data.
class InTags(val tag35: Option[String], val tag11: Option[String], val tag_109: Option[String], val tag_58: Option[String])
This following code takes a string and converts it into a Int -> String map by seperating on an equals sign.
val message= FIXMessage("8=FIX.4.29=25435=D49=REDACTED56=REDACTED115=REDACTED::::::::::CENTRAL34=296952=20151112-17:11:1111=Order7203109=CENTRAL1=TestAccount63=021=155=CSCO48=CSCO.O22=5207=OQ54=160=20151112-17:11:1338=5000040=244=2815=USD59=047=A13201=CSCO.O13202=510=127
")
val tag58 = message.fields(Some(58)).getOrElse("???")
val in_messages= new InTags(message.fields(Some(35)), message.fields(Some(11)), message.fields(Some(109)), Some(tag58))
println(in_messages.tag_109.getOrElse("???"))
where the FIXMessage object is defined as follows:
class FIXMessage (flds: Map[Option[Int], Option[String]]) {
val fields = flds
def this(fixString: String) = this(FIXMessage.parseFixString(Some(fixString)))
override def toString: String = {
fields.toString
}
}
object FIXMessage{
def apply(flds: Map[Option[Int], Option[String]]) = {
new FIXMessage(flds)
}
def apply(flds: String) = {
new FIXMessage(flds)
}
def parseFixString(fixString: Option[String]): Map[Option[Int], Option[String]] = {
val str = fixString.getOrElse("str=???")
val parts = str.split(1.toChar)
(for {
part <- parts
p = part.split('=')
} yield Some(p(0).toInt) -> Some(p(1))).toMap
}
}
The error I'm getting is ERROR key not found: Some(58) but doesnt the option class handle this? Which basically means that the string passed into the FIXMessage object doesnt contain a substring of the format 58=something(which is true) What is the best way to proceed?
You are using the apply method in Map, which returns the value or throw NoSuchElementException if key is not present.
Instead you could use getOrElse like
message.fields.getOrElse(Some(58), Some("str"))
This is somewhat of a theoretical question but something I might want to do. Is it possible to return multiple data data types from a Scala function but limit the types that are allowed? I know I can return one type by specifying it, or I can essentially allow any data type by not specifying the return type, but I would like to return 1 of 3 particular data types to preserve a little bit of type safety. Is there a way to write an 'or' in the return type like:
def myFunc(input:String): [Int || String] = { ...}
The main context for this is trying to write universal data loading script. Some of my users use Spark, some Scalding, and who knows what will be next. I want my users to be able to use a generic loading script that might return a RichPipe, RDD, or some other data format depending on the framework they are using, but I don't want to throw type safety completely out the window.
You can use the Either type provided by the Scala Library.
def myFunc(input:String): Either[Int, String] = {
if (...)
Left(42) // return an Int
else
Right("Hello, world") // return a String
}
You can use more than two types by nesting, for instance Either[A,Either[B,C]].
As already noted in comments you'd better use Either for this task, but if you really want it, you can use implicits
object IntOrString {
implicit def fromInt(i: Int): IntOrString = new IntOrString(None, Some(i))
implicit def fromString(s: String): IntOrString = new IntOrString(Some(s), None)
}
case class IntOrString(str: Option[String], int: Option[Int])
implicit def IntOrStringToInt(v: IntOrString): Int = v.int.get
implicit def IntOrStringToStr(v: IntOrString): String = v.str.get
def myFunc(input:String): IntOrString = {
if(input.isEmpty) {
1
} else {
"test"
}
}
val i: Int = myFunc("")
val s: String = myFunc("123")
//exception
val ex: Int = myFunc("123")
I'd make the typing by the user less implicit and more explicit. Here are three examples:
def loadInt(input: String): Int = { ... }
def loadString(input: String): String = { ... }
That's nice and simple. Alternatively, we can have a function that returns the appropriate curried function using an implicit context:
def loader[T]()(implicit context: String): String => T = {
context match {
case "RDD" => loadInt _ // or loadString _
}
}
Then the user would:
implicit val context: String = "RDD" // simple example
val loader: String => Int = loader()
loader(input)
Alternatively, can turn it into an explicit parameter:
val loader: String => Int = loader("RDD")
I have a function which takes optional parameters. However, these are not Option[?] but can be either set or null:
private def div(id: String = null, cssClass: String = null): JQuery = {
val optId = Option(id)
val optCssClass = Option(cssClass)
...
// deal with optId and optCssClass using the Scala-way™
...
}
I am using "null", which I know should be avoided like the plague. However, it allows me to write code like this:
div(id = "someId") // no cssClass
div(id = "otherId", cssClass = "someClass")
which to my eyes looks nicer than:
div(id = Some("someId")) // no cssClass
div(id = Some("otherId"), cssClass = Some("someClass"))
Is this a known / acceptable Scala pattern? (using null as default parameter values and converting to Option)
Or is it still heressy / bad-practice? If so, why?
why not replace null with empty string ?
private def div(id: String = "", cssClass: String = ""): JQuery = {
val optId = if(id.isEmpty) None else Some(id)
val optCssClass = if(cssClass.isEmpty) None else Some(cssClass)
...
// deal with optId and optCssClass using the Scala-way™
...
}
then you can do:
div(id = "someId") // no cssClass
div(id = "otherId", cssClass = "someClass")
One more approach I can suggest is a Builder Pattern
trait ElementBuilder {
def identified(id: String): ElementBuilder
def build: JQuery
}
case class DivElement(identifier: Option[String] = None)
extends ElementBuilder {
def identified(id: String) = this.copy(identifier = Option(id))
def build: JQuery = ??? // Smth like <div id={identifier}></div>
}
val builder = DivElement()
builder.identified("foo")
val element = builder.build
This approach allows you explicitly set parameters and then build you element by them
Most of the answers here are proposing some variant of the "null object" pattern, by denoting an empty String to mean "undefined" (as in val optId = if(id.isEmpty) None else Some(id))
The catch here is that an empty string might be a valid value! This is true of any String, though you can mitigate the problem by using something really outrageous, possibly involving non-printable characters. e.g:
val UndefinedString = "THIS-IS-A-REALLY-UNLIKELY-VALID-VALUE"
private def div(
id: String = UndefinedString,
cssClass: String = UndefinedString
): JQuery = {
val optId = Option(id) filter (_ != UndefinedString )
val optCssClass = Option(cssClass) filter (_ != UndefinedString )
...
// deal with optId and optCssClass using the Scala-way™
...
}
Better still, you could use a different type to denote your null object. As you can't subclass String you'll have to bump your params up the type hierarchy and make them CharSequences
object NullCharSeq extends CharSequence {
def charAt(idx: Int): Char = ???
def length(): Int = 0
def subSequence(start: Int, end: Int): CharSequence = this
def toString(): String = ???
}
def charSeqToOptStr(cs: CharSequence): Option[String] = cs match {
case NullCharSeq => None
case x => Option(x) map (_.toString)
}
private def div(
id: CharSequence = NullCharSeq,
cssClass: CharSequence = NullCharSeq
): JQuery = {
val optId = charSeqToOptStr(id)
val optCssClass = charSeqToOptStr(cssClass)
...
// deal with optId and optCssClass using the Scala-way™
...
}
It's a heavyweight pattern for one-shot usage, but the cost is quickly amortized if you use it a lot (NullCharSeq and charSeqToOptStr only need to be defined once in the codebase).
There's also zero risk of mistakenly passing your "undefined" String as though it were a valid value. Plus, you gain the ability to directly accept CharBuffer/StringBuffer/StringBuilder as your arguments.
I would also go for a special string like the empty string in #Jiafeng's answer, if this is a sensible value. You could also define a string, like
val NoId = "?"
def div(id: String = NoId) = id match {
case NoId => None
case x => Some(x)
}
Another approach would be to use another type which can be implicitly created from string or absence.
sealed trait MaybeId
implicit class Id(val name: String) extends MaybeId
case object NoId extends MaybeId
def div(id: MaybeId = NoId) = id match {
case NoId => None
case x: Id => Some(x.name)
}
Here is a general type that behaves like Option[A] with implicit conversion A => Some[A].