Argonaut is unable to be integrated with Spring's AbstractHttpMessageConverter?

113 views
Skip to first unread message

Winarto Zhao

unread,
Jan 6, 2014, 2:25:36 AM1/6/14
to argona...@googlegroups.com
Hi,

This is to continue the discussion on https://github.com/argonaut-io/argonaut/issues/77 which Mark had answered.

Firstly, I want to clarify that I'm not using scala just because "scala as a better syntax for java". As I have mentioned in the original question here, I'm new to scala and I'm still learning it. However, coming from Java (which I believe a lot of people does), I'm still trying to grasp the scala programming accent which is more of functional language than Java which is object oriented. Besides, by working in a large corporation which is very much rely on Java (both as language and platform), there should be a smooth transition from Java if I want to use Scala (both from software and people perspective).

Secondly, I know in Spring there is already a number of json converter which could do the work easily, however as I mentioned above, I'm learning scala and I want to get the understanding properly and try to use Argonaut as implementation of Spring's converter. As Mark had mentioned here that I might end up with either using (Java) reflection based is better or (Scala) Argonaut is better, I completely understand that. But again, I want to learn and by learning, I understand that I might be doing something very awkward and people will say "you're not supposed to do that way or this way", but I want to learn. So if there is a way to mixed Spring's converter with Argonaut, please help.

Mark's solution described in his comment is doing the job half done, as he mentioned that I still have to convert from Json object to my own object. I wanted to push the limit if there is a way that this can be done without manual conversion on my application.

Thanks

Wins

seantparsons

unread,
Jan 6, 2014, 5:04:24 AM1/6/14
to argona...@googlegroups.com
The only way I can see to bridge the two worlds would be to have a base implementation of the Spring interface that is implemented generically in terms of CodecJson for the type parameter T in AbstractHttpMessageConverter, then create implementations for each of the types you're interested in that resolve the implicit for CodecJson. 

Winarto Zhao

unread,
Jan 8, 2014, 10:07:52 PM1/8/14
to argona...@googlegroups.com
Do you mind to provide example on how to do that? I've tried many ways and the scala compiler keeps complaining that I don't have implicit conversion.

Regards,
Wins

seantparsons

unread,
Jan 12, 2014, 7:28:52 PM1/12/14
to argona...@googlegroups.com
You'd be better off if you supplied the code you have which doesn't work, rather than me coding an integration with Spring from scratch.

Winarto Zhao

unread,
Jan 12, 2014, 8:29:34 PM1/12/14
to argona...@googlegroups.com
This is the classesthat I created

The model classes

case class Currency(@BeanProperty currencyCode: String) 

object Currency {
  implicit def CurrencyCodecJson: CodecJson[Currency] = casecodec1(Currency.apply, Currency.unapply)("currencyCode")

  implicit def json2Currency(json: Json): Currency = json.as[Currency].toOption match {
    case Some(c) => c
    case None => null
  }
}

case class Person(@BeanProperty firstName: String, @BeanProperty lastName: String) 

object Person{
  implicit def PersonCodecJson: CodecJson[Person] = casecodec2(Person.apply, Person.unapply)("firstName","lastName")

  implicit def json2Person(json: Json): Person= json.as[Person].toOption match {
    case Some(p) => p
    case None => null
  }
}


And this is the converter

class ArgonautConverter extends AbstractHttpMessageConverter[Json](new MediaType("application", "json", Charset.forName("UTF-8")), new MediaType("application", "*+json", Charset.forName("UTF-8"))) {

  val supportedClasses = List(
    classOf[Currency],
    classOf[Person]
  )

  def supports(clazz: Class[_]): Boolean = {
    supportedClasses.contains(clazz)
  }

  def writeInternal(t: Json, outputMessage: HttpOutputMessage) = {
    outputMessage getBody() write t.spaces2.getBytes("UTF-8")
  }

  def readInternal(clazz: Class[_ <: Json], inputMessage: HttpInputMessage): Json = {
    Source.fromInputStream(inputMessage.getBody).getLines().mkString.parse.toEither match {
      case Left(message) => sys.error(message)
      case Right(json) => json

seantparsons

unread,
Jan 13, 2014, 3:36:16 PM1/13/14
to argona...@googlegroups.com
In the ArgonautConverter code do you have imports along the lines of the following?
import Currency._
import Person._

I could do with the exact error as well, as otherwise I don't know what implicit is missing from where.

As an aside be careful about using scala.io.Source full stop, the Source instance needs to be closed as in your case it will leak file handles continuously.

Sean.

Winarto Zhao

unread,
Jan 13, 2014, 10:07:23 PM1/13/14
to argona...@googlegroups.com
Hi Sean,

Thanks for your response.
I did all the necessary import. In fact, the code is working fine to convert from json string to Json object. However, what I need is not from json string to Json object. I need json string to the Currency or Person (or any further object) directly with this converter class. That's what I still don't know how to do.

Regards,
Winarto

seantparsons

unread,
Jan 14, 2014, 4:58:56 AM1/14/14
to argona...@googlegroups.com
You still haven't posted what your error is, so I still can't help you!

Winarto Zhao

unread,
Jan 14, 2014, 5:14:31 AM1/14/14
to argona...@googlegroups.com
The code doesn't produce error, but it only work halfway...

As I mentioned, what I need is from json string converted to model classes (e.g: Currency and Person in this case).
The code I posted only convert to Json, but I still have to convert to Currency and Person manually for each model. I need a generic converter that can convert based on the target class type.

Cheers,
Wins

seantparsons

unread,
Jan 14, 2014, 11:54:14 AM1/14/14
to argona...@googlegroups.com
Well you need to change AbstractHttpMessageConverter[Json] to AbstractHttpMessageConverter[Person] and similarly change parse to decode and add in a jencode to writeInternal, to get this to work for Person. It would be trivial to make that generic so that you can easily have an implementation for other types and not just code this whole instance to one type as well.

Sean.

Winarto Zhao

unread,
Jan 14, 2014, 8:01:59 PM1/14/14
to argona...@googlegroups.com
Hi Sean,

Not sure if you really understand my problem. I don't have problem if it is AbstractHttpMessageConverter[Person] or AbstractHttpMessageConverter[Currency]. But then I'll need to have so many classes to handle each different models.
What I need is one single class that can convert all of those models and any future without any modification on the converter. That's whay I meant by generic. There should not be any other converter for new model.

I hope I explain my problem better.

Regards,
Wins

seantparsons

unread,
Jan 20, 2014, 5:36:25 AM1/20/14
to argona...@googlegroups.com
I understand that, the only way I can see to achieve that would be to create a Map or similar of Class[_] to CodecJson[_], but it will have to involve some slightly nasty class casting in there to achieve that.

Sean.
Reply all
Reply to author
Forward
0 new messages