I can't derive a case class with many attributes. Strangely the output varies between SBT and gradle. A minimal reproducible example is found at https://github.com/geoHeil/pureconfig-issue, also the code is listed below:
sbt
sbt compile
[error] Caused by: java.lang.ClassNotFoundException: scala.runtime.LazyRef
gradle
./gradlew compileScala
ould not find implicit value for parameter reader: pureconfig.ConfigReader[Foo.XXX]
pureconfig.ConfigReader[XXX]
for code of:
object Foo extends App {
println("here")
case class MyNestedThing(foo: String)
case class XXX(
a: String,
b: String,
c: String,
d: String,
e: String,
f: String,
g: String,
h: String,
i: String,
j: String,
k: String,
l: String,
m: String,
n: String,
o: String,
p: String,
q: String,
r: String,
s: String,
t: String,
u: String,
v: String,
w: String,
x: String,
y: String,
z: String,
aa: String,
ab: String,
ac: String,
ad: String,
ae: String,
af: String,
ag: String,
ah: String,
ai: String,
aj: String,
ak: String,
al: String,
am: String,
an: String,
ao: String,
ap: String,
aq: String,
someLonglllllllllllllllllllllllllll: String,
so1meLonglllllllllllllllllllllllllll: String,
som2eLonglllllllllllllllllllllllllll: String,
ar: MyNestedThing,
as: MyNestedThing
)
pureconfig.ConfigReader[XXX]
}
Though works just fine when using:
object Foo extends App {
println("here")
case class MyNestedThing(foo: String)
case class XXX(
a: String,
b: String,
som2eLonglllllllllllllllllllllllllll: String,
ar: MyNestedThing,
as: MyNestedThing
)
pureconfig.ConfigReader[XXX]
}
edit
interestingly, I had a mixup in scala versions so when fixing it to be all of 2.11 SBT compiles fine, however gradle still shows the same problem.
When giving more memory to the scala compiler it works fine.
https://github.com/pureconfig/pureconfig/issues/391
tasks.withType(ScalaCompile) {
configure(scalaCompileOptions.forkOptions) {
jvmArgs = ["-Xss2m"]
}
}
Related
I am modeling some data types which are intrinsically having lots of fields.
Then I am having the ugly code, where the class's constructor is having a long list of arguments, as well as all its subclasses.
I kind of doubt whether BuilderPattern is a good solution for this.
For example, this is the generic class Transaction:
class Transaction(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
senderAccount: String,
senderName: String,
receiverAccount: String,
receiverName: String,
execDate: LocalSate,
createdDateTime: Instant)
This is the subclass A TxTypeA, which has some special fields specific for typeA:
class TxTypeA(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
senderAccount: String,
senderName: String,
receiverAccount: String,
receiverName: String,
execDate: LocalSate,
createdDateTime: Instant,
typeAField1: String,
typeAField2: String,
typeAField3: String
) extends Transaction(
source,
format,
id,
amount,
currency,
senderAccount,
senderName,
receiverAccount,
receiverName,
execDate,
createdDateTime)
This is the subclass B TxTypeB, which has some special fields specific for typeB:
class TxTypeB(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
senderAccount: String,
senderName: String,
receiverAccount: String,
receiverName: String,
execDate: LocalSate,
createdDateTime: Instant,
typeBField1: String,
typeBField2: String,
typeBField3: String,
typeBField4: String,
typeBField5: String,
typeBField6: String,
typeBField7: String
) extends Transaction(
source,
format,
id,
amount,
currency,
senderAccount,
senderName,
receiverAccount,
receiverName,
execDate,
createdDateTime)
Anyone has some better solution for this?
UPDATE:
In my project, I created another class called Party, which wrapped the Account and Name, but this is just releasing the pain, not solving the problem in the core.
case class Party(account: String, name: String)
class Transaction(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
senderParty: Party,
receiverParty: Party,
execDate: LocalSate,
createdDateTime: Instant)
You can tidy this up a bit by making Transaction a trait:
trait Transaction {
val source: String
val format: String
val id: String
val amount: Double
val currency: String
val senderAccount: String
val senderName: String
val receiverAccount: String
val receiverName: String
val execDate: LocalState
val createdDateTime: Instant
}
case class TxTypeA(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
senderAccount: String,
senderName: String,
receiverAccount: String,
receiverName: String,
execDate: LocalState,
createdDateTime: Instant,
typeAField1: String,
typeAField2: String,
typeAField3: String
) extends Transaction
case class TxTypeB(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
senderAccount: String,
senderName: String,
receiverAccount: String,
receiverName: String,
execDate: LocalState,
createdDateTime: Instant,
typeBField1: String,
typeBField2: String,
typeBField3: String,
typeBField4: String,
typeBField5: String,
typeBField6: String,
typeBField7: String
) extends Transaction
If you want, you can even combine these values into smaller case classes containing related fields, something like this:
case class Party(account: String, name: String)
trait Transaction {
val source: String
val format: String
val id: String
val amount: Double
val currency: String
val sender: Party
val receiver: Party
val execDate: LocalState
val createdDateTime: Instant
}
case class TxTypeA(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
sender: Party,
receiver: Party,
execDate: LocalState,
createdDateTime: Instant,
typeAField1: String,
typeAField2: String,
typeAField3: String
) extends Transaction
case class TxTypeB(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
sender: Party,
receiver: Party,
execDate: LocalState,
createdDateTime: Instant,
typeBField1: String,
typeBField2: String,
typeBField3: String,
typeBField4: String,
typeBField5: String,
typeBField6: String,
typeBField7: String
) extends Transaction
Or you can go further, passing Transaction as a parameter rather than extending it:
case class Party(account: String, name: String)
case class Transaction (
val source: String,
val format: String,
val id: String,
val amount: Double,
val currency: String,
val sender: Party,
val receiver: Party,
val execDate: LocalState,
val createdDateTime: Instant
)
case class TxTypeA(
transaction: Transaction,
typeAField1: String,
typeAField2: String,
typeAField3: String
)
case class TxTypeB(
transaction: Transaction,
typeBField1: String,
typeBField2: String,
typeBField3: String,
typeBField4: String,
typeBField5: String,
typeBField6: String,
typeBField7: String
)
It depends on your use-case and what is feasible. If you're doing something like formatting Json, I'd recommend extending it so the Json fields match up (or creating specific Reads etc).
Why not use case classes to model related information? e.g. the sender and reciever in the transaction can be modelled as seperate case classes;
case class Account(id: String, name: String)
class Transaction(
source: String,
format: String,
id: String,
amount: Double,
currency: String,
sender: Account
reciever: Account
execDate: LocalSate,
createdDateTime: Instant)
That way you reduce the amount of parameters in the constructor. You could then add helper methods to the Transaction class or implement a builder pattern, e.g. TransactionBuilder.withSender(senderName, senderAccountId)
In cases like this, I am looking to compose the fields in to other classes.
For example Transaction can be a composition of Sender, Receiver, Amount and so on.
I have a case class:
case class EvaluateAddress(addressFormat: String,
screeningAddressType: String,
value: Option[String]) {
}
This was working fine until I have a new use case where "value" parameter can be a class Object instead of String.
My initial implementation to handle this use case:
case class EvaluateAddress(addressFormat: String,
screeningAddressType: String,
addressId: Option[String],
addressValue: Option[MailingAddress]) {
#JsonProperty("value")
def setAddressId(addressId: String): Unit = {
val this.`addressId` = Option(addressId)
}
def this(addressFormat: String, screeningAddressType: String, addressId: String) = {
this(addressFormat, screeningAddressType, Option(addressId), None)
}
def this(addressFormat: String, screeningAddressType: String, address: MailingAddress) = {
this(addressFormat, screeningAddressType, None, Option(address))
}
}
but I don't feel this is a good approach and it might create some problem in future.
What are the different ways I can accomplish the same?
Edit: Is there a way I can create a class containing three parameters: ** addressFormat, screeningAddressType, value** and handle both the use cases?
You do not need to provide auxilliary constructors here and neither the setter. You could simply use the copy method provided by the case class.
For example:
case class MailingAddress(email:String)
case class EvaluateAddress(addressFormat: String,
screeningAddressType: String,
addressId: Option[String],
addressValue: Option[MailingAddress])
scala> val y = EvaluateAddress("abc", "abc", None, None)
y: EvaluateAddress = EvaluateAddress(abc,abc,None,None)
scala> y.copy(addressId = Some("addressId"))
res0: EvaluateAddress = EvaluateAddress(abc,abc,Some(addressId),None)
You can have a default value for fields in a case class.
So you can have the Optional fields default to None :
case class EvaluateAddress(addressFormat: String,
screeningAddressType: String,
addressId: Option[String] = None,
addressValue: Option[MailingAddress] = None)
Then when you create a new instance of EvaluateAddress, you can choose to pass a value for either of addressId, or addressValue or both ..or nothing at all.
I can't figure out why this doesn't work... During compile I get the following error:
[error] /Users/zbeckman/Projects/Glimpulse/Server-2/project/glimpulse-server/app/service/GPGlimpleService.scala:17: not enough arguments for method apply: (id: Long, glimpleId: Long, layerOrder: Int, created: Long, attachments: List[models.GPAttachment])models.GPLayer in object GPLayer.
[error] Unspecified value parameter attachments.
[error] private val layer1: List[GPLayer] = List(GPLayer(1, 42, 1, 9), GPLayer(2, 42, 2, 9))
For this case class... note the definition of an alternate constructor:
case class GPLayer(id: Long, glimpleId: Long, layerOrder: Int, created: Long, attachments: List[GPAttachment]) {
def this(id: Long, glimpleId: Long, layerOrder: Int, created: Long) = this(id, glimpleId, layerOrder, created, List[GPAttachment]())
}
GPLayer(1, 42, 1, 9)
is the same as writing
GPLayer.apply(1, 42, 1, 9)
So instead of defining an alternative constructor, you should define an alternative apply method in the companion object GPLayer.
case class GPLayer(id: Long, glimpleId: Long, layerOrder: Int, created: Long, attachments: List[GPAttachment])
object GPLayer {
def apply(id: Long, glimpleId: Long, layerOrder: Int, created: Long) = GPLayer(id, glimpleId, layerOrder, created, List[GPAttachment]())
}
If you want to call the altnernative constructor instead, you must add the new-keyword:
new GPLayer(1, 42, 1, 9)
Edit: As Nicolas Cailloux mentioned, your alternative constructor is really just providing a default value for the member attachments, so the best solution would actually be to not introduce a new method, but to specify this default value as follows:
case class GPLayer(id: Long, glimpleId: Long, layerOrder: Int, created: Long, attachments: List[GPAttachment] = Nil)
Note that in your case, you could just provide a default value for the last argument :
case class GPLayer(id: Long, glimpleId: Long, layerOrder: Int, created: Long, attachments: List[GPAttachment] = List())
xml data looks like
<bd>
<oied>
<oeuo>XYZWC999</oeuo>
<oedo>SorNbteluk=ONRM_ROOT_MO_R,SrobeNhbwk=XYZWC999,MoetxeoCt=XYZWC999</oedo>
<oesw>CXP9021776/2_R2CA15</oesw>
</oied>
<bi>
<bts>20150205141500Z</bts>
<gp>900</gp>
<bt>paaoCukStSteboshRrttcps</bt>
<bt>pptubthCaStctoSekSos</bt>
<bv>
<biod>MaebdlgeaooeEt=1,TparswotterNorok=1,Ntcp=Kub-9</biod>
<r>4578</r>
<r>10769</r>
</bv>
<bv>
<biod>MEegoedbaaloet=1,TreatoorNtosrpwk=1,Ntcp=1</biod>
<r>11021</r>
<r>86235</r>
</bv>
<bv>
<biod>MdaolaeeobeEgt=1,TretrowooNrtsapk=1,Nctp=Kub-7</biod>
<r>0</r>
<r>0</r>
</bv>
</bi>
</bd>
I am new to Scala, I could figure out the basic structure.
case class xmldata(oeuo : String, oedo : String, oesw: String, bts: String, gp : Int, btArray : List[String])
What is the optimized Scala case class (with collections) for this xml data?
It's just tree of case classes:
case class Bd(oied: Oied, bi: Bi)
case class Oied(oeuo: String, oedo: String, oesw: String)
case class Bi(bts: String, gp: String, bt: List[String], bv: List[Bv])
case class Bv(biod: String, r: List[String])
If order doesn't matter - you might use Set instead of List
You also might flatten it a bit (like in your solution), but it could be harder to map it with xml-binding tools then
case class Bd(oeuo: String, oedo: String, oesw: String, bts: String, gp: String, bt: List[String], bv: List[Bv])
The most flattened and least operable version (not recommended):
case class Bd(oeuo: String, oedo: String, oesw: String, bts: String, gp: String, bt: List[String], biods: List[String], rs: List[List[String]])
I am just dipping my toes into generics and am wondering if there is a better way to achieve the following:
I have a sealed trait that has an abstract name and an overridden equals(). I want the overridden equals to match on both type and name. Below is what I have.
sealed trait NamedCampaign[A <: NamedCampaign] {
def name: String
override def equals(obj: Any): Boolean = obj match {
case x: A => x.name == this.name
case _ => false
}
}
case class AdCampaign(name: String, objective: String, status: String, buyingType: String) extends NamedCampaign[AdCampaign]
case class AdSet(name: String, status: String, dailyBudget: Int, lifetimeBudget: Int, startTime: Int, endTime: Int, campaign: String) extends NamedCampaign[AdSet]
In layman's terms, I want two objects to be considered equal if they are the same class and have the same name. Is there a better/faster/more idiomatic way of doing this?
What you have can't work because of erasure. The type A isn't known at runtime.
Adapted from this related answer:
sealed trait NamedCampaign[A <: NamedCampaign] {
implicit def classTagA: ClassTag[A]
def name: String
override def equals(obj: Any): Boolean = obj match {
case classTagA(x) => x.name == this.name
case _ => false
}
}
case class AdCampaign(name: String, objective: String, status: String,
buyingType: String)(implicit val classTagA: ClassTag[AdCampaign])
extends NamedCampaign[AdCampaign]
case class AdSet(name: String, status: String, dailyBudget: Int,
lifetimeBudget: Int, startTime: Int, endTime: Int, campaign: String)
(implicit val classTagA: ClassTag[AdSet]) extends NamedCampaign[AdSet]
A better way to write this is with a canEqual method.
sealed trait NamedCampaign {
def name: String
def canEqual(that: Any): Boolean
override def equals(other: Any): Boolean = other match {
case that: NamedCampaign => (that canEqual this) &&
(this.name == that.name)
case _ => false
}
}
case class AdCampaign(name: String, objective: String, status: String,
buyingType: String) extends NamedCampaign {
override def canEqual(that: Any) = that.isInstanceOf[AdCampaign]
}
case class AdSet(name: String, status: String, dailyBudget: Int,
lifetimeBudget: Int, startTime: Int, endTime: Int, campaign: String)
extends NamedCampaign {
override def canEqual(that: Any) = that.isInstanceOf[AdSet]
}
My two cents: I don't think it's ever appropriate to override equals on a case class. You'll regret it the moment you ever want to compare all of the fields (which you're likely to want to do in, say, a unit test).