scala-jsonschema icon indicating copy to clipboard operation
scala-jsonschema copied to clipboard

support generating schema from runtime classes

Open igreenfield opened this issue 5 years ago • 13 comments

Let say I have TagType of Object and I want to generate schema for it.

igreenfield avatar Nov 19 '19 07:11 igreenfield

@igreenfield if this is still relevant, could you please describe why do you need this? what's the problem of generating schemas at compile time?

andyglow avatar Apr 17 '20 05:04 andyglow

I am using your lib to generate schema in the framework level so I don't have compile-time classes. in runtime I get the TagType of the class and I need a way to generate schema for that.

igreenfield avatar Apr 18 '20 21:04 igreenfield

TagType - you mean TypeTag, right? Let me clarify! You are saying that the model classes comes from some other jar. Right? But those classes are still scala classes (case classes, sealed traits, etc). Right? If so, you still can do

val myModelSchema = Json.schema[MyModelFromDependentJar]

andyglow avatar Apr 18 '20 22:04 andyglow

  1. TagType - you mean TypeTag, right? Yes
  2. the class is known only on runtime. not compile time so I can't

igreenfield avatar Apr 19 '20 08:04 igreenfield

This is interesting. How do you get typetag then? If it is a true runtime usually you work at Class[_] level. Right? You can create a typetag yourself out of class, but that is pretty tricky thing. So I am curious, how the things organized in your setup? Can you put some more detail on table?

andyglow avatar Apr 20 '20 03:04 andyglow

I am using MethodMirror of methods I will run later and for each method parameter, I need to create a schema. Does that answer your question?

igreenfield avatar May 04 '20 19:05 igreenfield

yes. ok, looks like i got it. you are developing a framework and you want end user to be able to receive json-schema generation functionality out of the box when using plain case classes for model definition. is that correct?

i will think about that. i didn't have intention to cover reflection-based models. but we'll see. until then can you tell me why you (as framework author) can't ask your end users to describe models in the way that framework would require? for example something like this would help

import json._

// framework api
trait ModelCompanion[T] {
  implicit def schema: Schema[T]
}

// end user code
case class Foo(bar: String, baz: Int)
object Foo extends ModelCompanion[Foo] {
  implicit def schema: Schema[Foo] = Json.schema[Foo]
}

// framework internals
def schemaFromClass(clazz: Class[_]): Schema[_] = {
  import scala.reflect.runtime.{ universe => ru }

  val mirror = ru.runtimeMirror(clazz.getClassLoader)
  val module = mirror.staticModule(clazz.getName)
  module.instance.asInstanceOf[ModelCompanion[_]].schema
}

i didn't try the code, but you've got the idea, right?

andyglow avatar May 05 '20 09:05 andyglow

  1. Yes.
  2. for now that what I am doing the framework. all the idea of the framework is to remove the need of the user to configure it, so no mistakes.

igreenfield avatar May 05 '20 09:05 igreenfield

you can generate this extra boilerplate yourself, right? i mean.. there are tools like

  • macro-annotation
  • compiler-plugin

or, in case you have time, contribution is appreciated.. i honestly don't know when i will have time for this problem

andyglow avatar May 06 '20 00:05 andyglow

OK , I will see if I have time for that contribution.

igreenfield avatar May 06 '20 02:05 igreenfield

I think i have a very similar use case: I would like to generate json schema for all classes within a package without writing code for each of it. At runtime it would be easy, just travers over all classes in the package using reflections or similar.

Is this somehow possible at compile time?

andyfr avatar Jun 29 '20 14:06 andyfr

Yeah I have the same situation as @igreenfield -- I've got a trait which handles serialization over the network, and would like to augment it with schema generation functionality.

Using the package as is means going through hundreds of classes and adding a method override to generate the schema. That in turn means importing the package all over the place, lots of boilerplate, and degrading legibility of otherwise very small case classes.

It would be super nice to be able to just declare the schema value in my trait! Thank you @andyglow for the suggestions on macro-annotation and compiler-plugin, I plan to take a look at that, though my experience with those is limited.

nightrise avatar Jul 12 '20 19:07 nightrise

hi @nightrise you guys probably already got it, got the fact that i personally strongly disagree with reflection based approach "the less reflection we use the better we sleep" - the slogan i would print on my t-short )

when i say disagree, i mean scala context. it's fine for java, that language is so restricted so reflection might seen a natural solution in that lands (oh, how many tears were shed because of this), but with scala you have much reacher platform to work directly with types

last couple of years my work requires me to use apache spark. besides the fact it it mostly written in scala, it uses reflection all over the place, and oh boy, how many inconsistencies we have because of that (randomly failed tests, jdk migration hell, etc) and how hard some time to debug that sort of issues

please think twice before getting into this reflection-based journey

andyglow avatar Aug 13 '20 03:08 andyglow