Reuse common structures (class, case classe, object) between jvm (e.g. play) / javascript (scala-js)

510 views
Skip to first unread message

jlchas...@gmail.com

unread,
Sep 4, 2014, 11:46:40 AM9/4/14
to scal...@googlegroups.com
Hi,

Hope you are well and enjoy scala-js as we do!

One of the advantage of scala-js is the ability to reuse structures in both environments (jvm and javascript), which imply to compile them with scalac and scala-js.
A practical example is a domain model composed of multiple traits, classes, case classes and objects.

A simple representation of the architecture of one's project would be:
- a common library:
  which define the domain model,
- a play application:
  dealing with data (e.g. access from/to database, convert to case classes), expose a REST api, convert model's classes to JSON,
- a scala-js web application (based on angularjs):
  which receive JSONised data structures and convert them back to model case classes, display their content nicely to the users.

The conversion from/to JSON might be done using upickle or scala-js-pickling (we are using the 2nd option).
So far, so good.

Now the question:

Structures within the models are not annotated by @JSExport as they need to be compiled in both environment (without scala-js dependency).
However, these classes need to be manipulated by the javascript itself (such as being displayed within the html by angular, e.g. <p ng-repeat="item in itemList"> {{ item }} </p>).
At these crucial moments, we need to access fields which are not exported.
Howe do we do?

Several options popped up quickly in our mind:
- re-implementing all the classes with @JSExport annotations and implicit conversions: we loos a huge benefit from scala-js,
- implementing a macro which add @JSExport automatically to all fields of the classes within a given package, might be interesting but time consuming to write,
- magical solution from the scala-js guys? :D

As a side note, still from javascript, how do we iterate through Lists/Maps used in the structures?

Thanks for your help!

Cheers,

Jean Luc

Haoyi Li

unread,
Sep 4, 2014, 12:41:03 PM9/4/14
to jlchas...@gmail.com, scal...@googlegroups.com
Another option would be to implement your own stub js.annotation.JSExport class which does nothing, but which can be used on the server without the ScalaJS dependency. That way the server-code will see it and do nothing (but still compile!) while the client-code will do the right JSExport thing.


--
You received this message because you are subscribed to the Google Groups "Scala.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-js+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/scala-js/ac268225-7cb8-4538-a1ae-6611c916e998%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Justin du coeur

unread,
Sep 4, 2014, 12:47:07 PM9/4/14
to Haoyi Li, jlchas...@gmail.com, scal...@googlegroups.com
On Thu, Sep 4, 2014 at 12:40 PM, Haoyi Li <haoy...@gmail.com> wrote:
Another option would be to implement your own stub js.annotation.JSExport class which does nothing, but which can be used on the server without the ScalaJS dependency. That way the server-code will see it and do nothing (but still compile!) while the client-code will do the right JSExport thing.

That's a sensible and fairly minimal solution -- it fits with the rationale of JSExport, while not doing too much violence to the JVM side.  (Vincent, should I explore adding this to the play-scalajs-example?)

Haoyi Li

unread,
Sep 4, 2014, 12:51:05 PM9/4/14
to Justin du coeur, jlchasseriau, scal...@googlegroups.com
I'd go further and say that this (and similar things, like JSExportAll, JSExportName and JSExportDescendentObjects) should all be provided by a lightweight library that ScalaJS itself depends on (scala-js-stubs?). That way other people could depend on scala-js-stubs and get these things for free rather than having to manually implement shims ourselves.

Justin du coeur

unread,
Sep 4, 2014, 12:54:04 PM9/4/14
to Haoyi Li, jlchasseriau, scal...@googlegroups.com
Makes sense...

Dan Di Spaltro

unread,
Sep 4, 2014, 1:36:46 PM9/4/14
to Justin du coeur, Haoyi Li, jlchasseriau, scal...@googlegroups.com
Couldn't you also use scala.js like a provided dependency (one that is compile time only)? Side note, JSExport is only useful if you're planning on using the objects from real javascript.  If you're using the objects in scala.js all the way down it's not needed right?

-Dan


Makes sense...
--
You received this message because you are subscribed to the Google Groups "Scala.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-js+u...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Dan Di Spaltro

jlchas...@gmail.com

unread,
Sep 5, 2014, 3:11:48 AM9/5/14
to scal...@googlegroups.com, jlchas...@gmail.com
Yes, absolutely, that is another option we thought about (forgotten in the previous list).
In the current state of the art, it also seems the best and only one.

@Dan, yes, JSExport is only needed when using the object from javascript itself, which is the case (javascript object are used within the html by angular's dynamic tags).

Other ideas?

Wish you a nice day!

Sébastien Doeraene

unread,
Sep 5, 2014, 3:50:12 AM9/5/14
to jlchas...@gmail.com, scal...@googlegroups.com
Hi,

The shim @JSExport for the JVM lib is definitely the best thing to do.
We could indeed probably publish a tiny JVM-only lib with all the shims of Scala.js.

Cheers,
Sébastien


SemanticBeeng

unread,
Jan 4, 2015, 10:55:02 PM1/4/15
to scal...@googlegroups.com
Hi Jean Luc

Here's a sample project with the intent to apply Scala.JS to non trivial shared business logic and data,


I cloned a repo from Haoyi and am applying what he has showed in a number of occasions.
At this point it is taking the use of Autowire a step further from where the public examples leave off.

Question for you guys,
Would it make sense to create an export annotation for case classes that save the developer from having to export every field?
Ideally it would auto export fields of cases classes...

see

@JSExport
case class EmailAddress(@(JSExport @field) name: String,  @(JSExport @field) domain: String)


Thanks

SemanticBeeng

unread,
Jan 4, 2015, 11:06:39 PM1/4/15
to scal...@googlegroups.com
Maybe we could write

@JSExport(allFields="true")
case class EmailAddress(name: String,  domain: String)

and even make allFields = true by default

Sébastien Doeraene

unread,
Jan 5, 2015, 12:11:48 AM1/5/15
to SemanticBeeng, scal...@googlegroups.com

Hi,

That's @JSExportAll
http://www.scala-js.org/api/scalajs-library/0.5.5/index.html#scala.scalajs.js.annotation.JSExportAll

Cheers,
Sébastien

--
You received this message because you are subscribed to the Google Groups "Scala.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-js+u...@googlegroups.com.

SemanticBeeng

unread,
Jan 5, 2015, 8:41:42 AM1/5/15
to scal...@googlegroups.com, semanticbeen...@gmail.com
Thank you, Sébastien.
Seems that @JSExport is also required beside @JSExportAll.


I will assume this is the intent. 
Initially I expected @JSExportAll to ... override @JSExport so to speak.

Sébastien Doeraene

unread,
Jan 5, 2015, 8:57:37 AM1/5/15
to SemanticBeeng, scal...@googlegroups.com
Yes, @JSExport is necessary in addition to @JSExportAll, in the sense that are orthogonal and do different things:
* @JSExport exports the constructor of the class, but not the members. It is necessary to be able to instantiate the class.
* @JSExportAll exports all the members of the class, but not the constructors. It is necessary to access the members.

Cheers,
Sébastien

Reply all
Reply to author
Forward
0 new messages