I would like to make the prepareStatement serializable
A preparedStatement is not serializable. I have to build a serializable structure that wraps the call and the parameters to control the construction of the said statement during the deserialization
Here are the classes I created to wrap the PrepareStament
import java.sql._
import java.sql.SQLException
import java.util
import java.util.Collections
import avro.shaded.com.google.common.collect.ImmutableMap
import scala.collection.immutable.HashMap
import scala.collection.mutable
class WrappedConnection(var delegate: Connection) extends Serializable {
def prepareStatement(sql: String): WrappedPreparedStatement = {
val ps = delegate.prepareStatement(sql)
new WrappedPreparedStatement(sql, ps)
}
// delegate all Connection methods to the delegate
}
class WrappedPreparedStatement(var sql: String, var delegate: PreparedStatement) extends Serializable {
private var parameters: mutable.Map[Integer, Object] = mutable.Map.empty[Integer, Object]
override def toString: String = sql
def apply( delegateVar: PreparedStatement) {
delegate = delegateVar
parameters = mutable.Map.empty[Integer, Object]
}
def getParameters = parameters
// TODO: many methods to delegate
#throws[SQLException]
def setString(parameterIndex: Int, x: String): Unit = {
delegate.setString(parameterIndex, x)
parameters.put(parameterIndex, x)
}
#throws[SQLException]
def executeQuery = { // perhaps you might want to do some logging here?
delegate.executeQuery
}
// delegate all PreparedStatement methods to the delegate
}
object WrappedConnection {
def apply(delegate: Connection): WrappedConnection = new WrappedConnection(delegate)
}
This is the test code
val connection = MsSqlUtils.createConnectionFactory(config)
val conn = connection()
val wrapperConn = WrappedConnection(conn)
val statement = wrapperConn.prepareStatement("select * from users")
Currently, my problem is to access the variables of my prepareStatement object and create get functions that will return them.
When I talk about variables I talk about the one shown in the picture below not the one in the querie
Anyone know how to access these variables?
Hi guys i'm a beginner and i have a problem with this code is. I am trying to create an arraylist but it can only use the default class Members
The problem lies in here var memberList : ArrayList[Members] with an error message of :
Error:(13, 30) not found: type Members
var memberList : ArrayList[Members]
Does anyone know a workaround with it?
The sample code is below.
import java.util.{ArrayList}
abstract class Groups(){
val groupName: String
val groupType: String
var memberList : ArrayList[Members]
def addMember(enter: String): Unit = {
memberList.add(enter)
}
def deleteMember(del: String): Any = {
memberList.remove(del)
}
}
class Members(var name: String, var permission: String){
}
I have a HelperMethod class.
class HelperMethods {
def getUniqueID(): UUID = {
UUID.randomUUID()
}
def bucketIDFromEmail(email:String): Int = {
val bucketID= email(0).toInt
println("returning id "+bucketID+" for name "+email)
bucketID
}
}
And an object which has an instance of HelperMethods
package object utilities{
private val helper = new HelperMethods()
def getUniqueID(): UUID = helper.getUniqueID()
def bucketIDFromEmail(email:String): Int = helper.bucketIDFromEmail(email)
}
I wrote a spec to test that my mock works correctly.
class UserControllerUnitSpec extends PlaySpec {
val mockHelperMethods = mock(classOf[HelperMethods])
when(mockHelperMethods.getUniqueID()).thenReturn(UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210"))
when(mockHelperMethods.bucketIDFromEmail(ArgumentMatchers.any[String])).thenReturn(1)
"mocking helper class " should {
"work" in {
val bucketId = utilities.bucketIDFromEmail("t#t.com")
println("user keys are " + userKeys)
val id: UUID = utilities.getUniqueID()
println("got id " + userKeys)
bucketId mustBe 1
id mustBe UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210")
}
}
}
the test fails with reason 116 was not equal to 1. This corresponds to line
bucketId mustBe 1 in the spec. I can see the print returning id 116 for name t#t.com. I shouldn't see it as I am trying to mock this class. I suspect that it could be because the utilities object is getting created before the statement val mockHelperMethods = mock(classOf[HelperMethods]) in the spec.
Question 2- Is there a way to mock HelperMethods and make utilities use the mocked class?
You have mocked HelperMethods but not utilities.
Question 2- Is there a way to mock HelperMethods and make utilities use the mocked class?
It is not possible to mock an object.
If you want, you have to extract the behavior in a trait.
Here is a solution that would work:
package utils
// move the behavior to a trait:
trait UtitilitiesTrait {
private[utils] def helper = new HelperMethods()
def getUniqueID(): UUID = helper.getUniqueID()
def bucketIDFromEmail(email: String): Int = helper.bucketIDFromEmail(email)
}
// provide an object for real use
object Utilities extends UtitilitiesTrait
// override helper for test mock
object TestUtilities extends UtitilitiesTrait {
private[utils] override def helper = mock(classOf[HelperMethods])
}
And here is your test:
class UserControllerUnitSpec extends PlaySpec {
val mockHelperMethods = mock(classOf[HelperMethods])
object TestUtilities extends UtitilitiesTrait {
private[utils] override def helper = mockHelperMethods
}
when(mockHelperMethods.getUniqueID()).thenReturn(UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210"))
when(mockHelperMethods.bucketIDFromEmail(ArgumentMatchers.any[String])).thenReturn(1)
"mocking helper class " should {
"work" in {
val bucketId = TestUtilities.bucketIDFromEmail("t#t.com")
println("user keys are " + userKeys)
val id: UUID = TestUtilities.getUniqueID()
println("got id " + userKeys)
bucketId mustBe 1
id mustBe UUID.fromString("87ea52b7-0a70-438f-81ff-b69ab9e57210")
}
}
}
The typical pattern that enables mocking objects used internally is to inject them, or at least provide a way to inject an alternate.
Since Utilities is an object, you can't inject using a constructor. You could still introduce a setter method.
If you'd like to discourage use of the setter for anything other than unit tests, make it package-private, and you might also prefix the name with "qa":
private[utils] def qaSetHelperMethods(qaHelper: HelperMethods): Unit
I have some working jackson scala module code for roundtripping scala case classes. Jackson worked great for flat case classes but when I made one which contains a list of other case classes the amount of code I seemed to need was a lot. Consider:
abstract class Message
case class CardDrawn(player: Long, card: Int, mType: String = "CardDrawn") extends Message
case class CardSet(cards: List[CardDrawn], mType: String = "CardSet") extends Message
To get the CardSet to roundtrip to/from json with jackson scala module I used a custom serializer/deserializer written in java:
object ScrumGameMashaller {
val mapper = new ObjectMapper()
val module = new SimpleModule("CustomSerializer")
module.addSerializer(classOf[CardSet], new CardSetSerializer)
module.addDeserializer(classOf[CardSet], new CardSetDeserializer)
val scalaModule = DefaultScalaModule
mapper.registerModule(scalaModule)
mapper.registerModule(module)
def jsonFrom(value: Any): String = {
import java.io.StringWriter
val writer = new StringWriter()
mapper.writeValue(writer, value)
writer.toString
}
private[this] def objectFrom[T: Manifest](value: String): T =
mapper.readValue(value, typeReference[T])
private[this] def typeReference[T: Manifest] = new TypeReference[T] {
override def getType = typeFromManifest(manifest[T])
}
private[this] def typeFromManifest(m: Manifest[_]): Type = {
if (m.typeArguments.isEmpty) { m.runtimeClass }
else new ParameterizedType {
def getRawType = m.runtimeClass
def getActualTypeArguments = m.typeArguments.map(typeFromManifest).toArray
def getOwnerType = null
}
}
with serializer:
public class CardSetSerializer extends JsonSerializer<CardSet> {
#Override
public void serialize(CardSet cardSet, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeArrayFieldStart("cards");
List<CardDrawn> cardsDrawn = cardSet.cards();
scala.collection.Iterator<CardDrawn> iter = cardsDrawn.iterator();
while(iter.hasNext()){
CardDrawn cd = iter.next();
cdSerialize(jgen,cd);
}
jgen.writeEndArray();
jgen.writeStringField("mType", "CardSet");
jgen.writeEndObject();
}
private void cdSerialize(JsonGenerator jgen, CardDrawn cd) throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeNumberField("player", cd.player());
jgen.writeNumberField("card", cd.card());
jgen.writeEndObject();
}
}
and matching deserializer:
public class CardSetDeserializer extends JsonDeserializer<CardSet> {
private static class CardDrawnTuple {
Long player;
Integer card;
}
#Override
public CardSet deserialize(JsonParser jsonParser, DeserializationContext cxt) throws IOException, JsonProcessingException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode root = oc.readTree(jsonParser);
JsonNode cards = root.get("cards");
Iterator<JsonNode> i = cards.elements();
List<CardDrawn> cardObjects = new ArrayList<>();
while( i.hasNext() ){
CardDrawnTuple t = new CardDrawnTuple();
ObjectNode c = (ObjectNode) i.next();
Iterator<Entry<String, JsonNode>> fields = c.fields();
while( fields.hasNext() ){
Entry<String,JsonNode> f = fields.next();
if( f.getKey().equals("player")) {
t.player = f.getValue().asLong();
} else if( f.getKey().equals("card")){
t.card = f.getValue().asInt();
} else {
System.err.println(CardSetDeserializer.class.getCanonicalName()+ " : unknown field " + f.getKey());
}
}
CardDrawn cd = new CardDrawn(t.player, t.card, "CardDrawn");
cardObjects.add(cd);
}
return new CardSet(JavaConversions.asScalaBuffer(cardObjects).toList(), "CardSet");
}
}
This seems like a lot code to deal with something fairly vanilla in the scala. Can this code be improved (what did I miss that jackson has to make this easy)? Else is there a library which will do structured case classes automatically? The jerkson examples looked easy but that seems to have been abandoned.
Argonaut does a great job. Mark Hibbard helped me out with getting the example below working. All that is needed is to create a codec for the types and it will implicitly add an asJson to your objects to turn them into strings. It will also add a decodeOption[YourClass] to strings to extract an object. The following:
package argonaut.example
import argonaut._, Argonaut._
abstract class Message
case class CardDrawn(player: Long, card: Int, mType: String = "CardDrawn") extends Message
case class CardSet(cards: List[CardDrawn], mType: String = "CardSet") extends Message
object CardSetExample {
implicit lazy val CodecCardSet: CodecJson[CardSet] = casecodec2(CardSet.apply, CardSet.unapply)("cards","mType")
implicit lazy val CodecCardDrawn: CodecJson[CardDrawn] = casecodec3(CardDrawn.apply, CardDrawn.unapply)("player", "card", "mType")
def main(args: Array[String]): Unit = {
val value = CardSet(List(CardDrawn(1L,2),CardDrawn(3L,4)))
println(s"Got some good json ${value.asJson}")
val jstring =
"""{
| "cards":[
| {"player":"1","card":2,"mType":"CardDrawn"},
| {"player":"3","card":4,"mType":"CardDrawn"}
| ],
| "mType":"CardSet"
| }""".stripMargin
val parsed: Option[CardSet] =
jstring.decodeOption[CardSet]
println(s"Got a good object ${parsed.get}")
}
}
outputs:
Got some good json {"cards":[{"player":"1","card":2,"mType":"CardDrawn"},{"player":"3","card":4,"mType":"CardDrawn"}],"mType":"CardSet"}
Got a good object CardSet(List(CardDrawn(1,2,CardDrawn), CardDrawn(3,4,CardDrawn)),CardSet)
The question is old but maybe someone could still find it helpful. Apart from Argonaut, Scala has several Json libraries. Here you can find a list of them updated to the beginning of 2016 (and it still gives you a good overall picture).
Most of them (probably all) should allow you to come up with a drier version of your custom serializer/deserailizer. My preference goes to json4s which aims to provide a single AST across multiple libraries including Jackson (a bit like slf4j does for logging libraries). In this post you can find a working example of a Json custom serializer/deserializer using Json4s and Akka Http.
As far as I understand it, Scala creates an anonymous class if I create a class using the new keyword and follow the class name with a constructor:
class MyClass {
def doStuff() {
// ...
}
}
val mc = new MyClass {
doStuff()
}
The nice thing being that all the code in the constructor is in the scope of the new object.
Is there a way I can reproduce this syntax where the class is created by a factory method rather than the new keyword? i.e. make the following code work:
val mf = new MyFactory
val mc = mf.MyClass {
doStuff()
}
I can't find a way to do it but Scala has so much to it that this might be pretty easy!
Using an import as suggested by #Ricky below I can get:
val mf = MyFactory;
val mc = mf.MyClass
{
import mc._
doStuff()
}
(Where the blank line before the block is needed) but that code block is not a constructor.
You can do this, but you still have to keep the new keyword, and create the nested class as a path-dependent type:
class Bippy(x: Int) {
class Bop {
def getIt = x
}
}
val bip = new Bippy(7)
val bop = new bip.Bop
bop.getIt // yields 7
val bop2 = new bip.Bop{ override def getIt = 42 }
bop2.getIt // yields 42
I don't think it's possible. However, a common pattern is to add a parameter to factory methods which takes a function modifying the created object:
trait MyClass {
var name = ""
def doStuff():Unit
}
class Foo extends MyClass {
def doStuff() { println("FOO: " + name) }
}
trait MyClassFactory {
def make: MyClass
def apply( body: MyClass => Unit ) = {
val mc = make
body(mc)
mc
}
}
object FooFactory extends MyClassFactory {
def make = new Foo
}
You can then create and modify instance with a syntax close to your example:
val foo = FooFactory { f=>
f.name = "Joe"
f.doStuff
}
It sounds like you're just looking to mix in a trait. Instead of calling myFactoryMethod(classOf[Foo]] which ideally would do (if Scala permitted it):
new T {
override def toString = "My implementation here."
}
you can instead write
trait MyImplementation {
override def toString = "My implementation here."
}
new Foo with MyImplementation
However, if you are just looking to get the members of the new object accessible without qualification, remember you can import from any stable identifier:
val foo = new Bar
import foo._
println(baz) //where baz is a member of foo.