I'm trying to read my config file into my case class whose one of attribute is a Map of Enumeratum key and Case Class value by using pureconfig and pureconfig-enumeratum libraries version 0.14.0 with scala 2.11.
When I change the Map key from Enumeratum key to String, it works, but it does not work with Enum key.
import enumeratum.EnumEntry.{Hyphencase}
import enumeratum._
import pureconfig.{ConfigSource}
import pureconfig.generic.auto._
import pureconfig.module.enumeratum._
object CheckPureConfig extends App {
private val myConf = ConfigSource.default.loadOrThrow[SsystemConf]
println(myConf)
}
case class SsystemConf(target: Map[Ssystem, MyConfig])
case class MyConfig(path: Ssystem, link: String)
sealed abstract class Ssystem(myField: String) extends EnumEntry with Hyphencase{
def printit() = myField
}
object Ssystem extends Enum[Ssystem] {
val values = findValues
case object MyEnumA extends Ssystem("testFieldEnum1")
case object MyEnumB extends Ssystem("testFieldEnum2")
}
And this is my application.conf
target {
my-enum-a= {
path : "samplepath1"
link : "samplehttp1"
}
my-enum-b = {
path : "samplepath2"
link : "samplehttp2"
}
}
You have to use configurable converter to tell pureconfig how to transform your enum to Map keys. You have genericMapReader for that:
implicit def enumMapReader[V: ConfigReader]: ConfigReader[Map[Ssystem, V]] =
genericMapReader { name =>
Ssystem.withNameOption(name)
.fold[Either[String, Ssystem]](Left(s"$name is not enum"))(Right(_))
}
I would like to align case objects extending some class with scalafmt:
sealed abstract class AClass(id: String)
object AClass {
case object Abc extends AClass("1")
case object De extends AClass("2")
case object Fghi extends AClass("3")
}
I have tried the following with in .scalafmt.conf with no success:
align.tokens=[
{ code = "extends", owner = "case object" }
]
What options should I use?
If I want to modify one single parameter in a constructor.
In the Scala case class, the apply method will be overridden twice. Unless apply applies ( no pun ) to auxiliary constructor.
Related to
Modifying case class constructor parameter before setting value
How to override apply in a case class companion
How one can modify one single input from a constructor ?
Criteria :
The class must hold immutable data. All data must be accessible.
Note it doesn't have to be case class.
Additionally , no need to use the apply method.
no extra unused parameters. In the example below, _fistName is still accessible but unused.
case class Person(
lastName: String,
_fistName: String, ... )
{ lazy val fistName = _fistName.toLowerCase }
Here are two simple approaches.
Using class:
class Person(first: String, last: String) {
val firstName = first.toLowerCase
val lastName = last.toLowerCase()
}
val person = new Person("Adam", "Smith")
println(person.firstName + " " + person.lastName) // adam smith
Using trait + object's apply():
trait Person {
val firstName: String
val lastName: String
}
object Person {
def apply(first: String, last: String) = new Person {
override val firstName: String = first.toLowerCase
override val lastName: String = last.toLowerCase
}
}
val person = Person("Adam", "Smith")
println(person.firstName + " " + person.lastName) // adam smith
Note that classes must be instantiated with new, while traits (created with apply()) don't.
Why no case classes? Well, they are designed to serve as ADTs (abstract data types). Basically, they are thought of as containers for some data without any logic. That's why they get apply() out-of-the-box. If you want to override it, then means your class doesn't have the semantics of a case class.
I can see that #prayag took the effort of trying to help you force it into a case class, but seriously, if it doesn't have to be one (and you said so in the question), then don't make it one.
The reference you had posted seems to have lot of answers as well.
Two simple ways I could think of
make it abstract case class and define companion object which would mutate the value you want
define the member of case class as var and mutate it.
eg. (using scalatest)
class CaseClassSpecs extends FunSpec {
describe("case class modify") {
it("APPROACH 1 : modifies abstract case class member") {
object Item {
def apply(itemId: String, itemName: String) :Item = new Item(itemId.toLowerCase, itemName) {}
}
abstract case class Item private (val itemId: String, itemName: String)
val item1 = Item("SKU-ONE", "Shirts")
assert(item1.itemId == "sku-one")
assert(item1.itemName == "Shirts")
}
it("APPROACH 2 : modifies case class member which is var") {
case class Item (var itemId: String, itemName: String) {
itemId = itemId.toLowerCase()
}
val item1 = Item("SKU-ONE", "Shirts")
assert(item1.itemId == "sku-one")
assert(item1.itemName == "Shirts")
}
}
}
Class parameters are not necessarily class members. You can have class parameters that do not become class members.
Method 1
class Foo(bar0: String) {
val bar = bar0.toLowerCase()
}
#main
def main(): Unit = {
println(Foo("AsDfGh").bar)
}
prints:
asdfgh
and the decompiled code is:
public class Foo {
private final String bar;
public Foo(final String bar0) {
this.bar = bar0.toLowerCase();
}
public String bar() {
return this.bar;
}
}
You see, bar0 is a "temporary" value, it does not become a field because it is not referenced.
So if you want to change a value, just do not use the original value in the methods.
Method 2
For case classes, it does not seem to work in 2022, but here is another trick:
case class Point (x: Double, y: Double)
class PolarPoint(r: Double, alpha: Double) extends Point(r*Math.cos(alpha), r*Math.sin(alpha))
Here r and alpha do not become members of PolarPoint.
If you don't need two types, you can make the 1st constructor protected:
case class Foo protected(x:Int)
class FooImpl(x0:Int) extends Foo(myFunc(x0))
You will reference objects as Foos but create FooImpls.
Method 3
Your class can have multiple parameter lists and implicits:
class Qux(x:String)(implicit val y:String = x.toLowerCase())
is converted to:
public class Qux {
private final String y;
public static String $lessinit$greater$default$2(String var0) {
return Qux$.MODULE$.$lessinit$greater$default$2(var0);
}
public Qux(final String x, final String y) {
this.y = y;
}
public String y() {
return this.y;
}
}
You see that here only y becomes a field.
I created a class Project extending a Model:
abstract class Model
case class Project(...) extends Model
and an object Table extending Base:
abstract class Base {
val tableForm: Form[Model]
}
object Table extends Base {
val tableForm: Form[Project] = (...)
}
Why is it that it won't compile and how can I fix it? ("overriding method/value tableForm in class Base of type => Form[Model]")
I just wanted to force all subclasses of Base to have a tableForm attribute.
Because Form[Project] is not a subclass of Form[Model]. So the compiler complains about incompatible type in overriding value.
Form[T] is invariant. You can read the variance doc
To fix this, you can add a type parameter to Base.
abstract class Base[M <: Model] {
val tableForm: Test[M]
}
object Table extends Base[Project] {
val tableForm: Test[Project] = ???
}
Using Lift with Squeryl, how can I make two classes a subclass of the same class?
My classes look like the following:
class SubClass1 extends Record[SubClass1] with KeyedRecord[SubClass1] with CreatedUpdated[SubClass1] {
val id = ...
val field1a = StringField(...)
...
}
class SubClass2 extends Record[SubClass2] with KeyedRecord[SubClass2] with CreatedUpdated[SubClass2] {
val id = ...
val field2a = StringField(...)
}
I want SubClass1 and SubClass2 each to be a child class of some other class, say MyParentClass. So I would think that I would have to do something like this:
abstract class MyParentClass extends Record[MyParentClass] with KeyedRecord[MyParentClass] with CreatedUpdated[MyParentClass] {}
and then
class SubClass1 extends MyParentClass {
val id = ...
val field1a = StringField(...)
...
}
class SubClass2 extends MyParentClass {
val id = ...
val field2a = StringField(...)
...
}
This gives me errors, such as the fields (StringField) etc. not conforming to the right type. Any suggestions on how to do this?
Thanks,
You abstract superclass can't define a concrete type parameter, since it needs to be overriden by the subclasses. Try:
abstract class MyParentClass[A <: MyParentClass]
extends Record[A] with KeyedRecord[A] with CreatedUpdated[A]
Then:
class SubClass extends MyParentClass[SubClass]