Post on 22-Apr-2015
description
Developing Java EE 7 Applications with
Scala (CON2664) Demystifying the Object-Functional
Peter Pilgrim Scala and Java EE
Independent contractor
@peter_pilgrim
Xenonique
Creative Commons 2.0 Attribution-NonCommercial-ShareAlike 2.0 UK: England & Wales (CC BY-NC-SA 2.0 UK) https://creativecommons.org/licenses/by-nc-sa/2.0/uk/
• Share — copy and redistribute the material in
any medium or format • Adapt — remix, transform, and build upon the
material • The licensor cannot revoke these freedoms as
long as you follow the license terms.
2
Xenonique
About Me • Scala and Java EE developer independent
contractor • Digital transformation / e-commerce • Java Champion • Working on the JVM since 1998
3
Xenonique 4
Java EE 7 Developer Handbook September 2013 Packt Publishing Digital Java EE 7 Web APPS December 2014
Xenonique 5
Agenda • Scala Technology • Java EE 7 • CDI • JSF, Servlets • JAX-RS, JMS
Xenonique 6
Xenonique 7
#1 Scala Object-functional Since 2003 Statically typed programming Scalable Language Inventor: Professor Martin Odersky, EPFL, Typesafe
Xenonique 8
#1 Scala Pattern Matching Case Classes Traits, Mix-ins, Collections Expressions, In-fix operators Functions, Closures, Control Abstractions Extension through Library functions
Xenonique 9
#1 Scala Gradle, Gradle, Gradle v2.0 Groovy assembler, builder Comprehensible, Configurable, Flexible Works with Scala since Gradle v1.7 With Gradle, building WAR files is very straightforward
Xenonique
Scala Language
var age: Int = 37 val pi: Double = 3.141596527 val text: String = "human nature" val r = if (age >= 18 ) "Adult" else "Child"
10
Xenonique
Scala Test #1
import collection.mutable.Stack import org.scalatest._ import org.scalatest.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) class StackSpec extends FlatSpec with Matchers { /* ... */
}
11
Xenonique
Scala Test #2
class StackSpec extends FlatSpec with Matchers { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) stack.pop() should be (2) stack.pop() should be (1) } /* ... */ }
12
Xenonique
Scala Test #3
class StackSpec extends FlatSpec with Matchers { /* ... */ it should "throw NoSuchElementException if an empty stack is popped" in { val emptyStack = new Stack[Int] a [NoSuchElementException] should be thrownBy {
emptyStack.pop() } } }
13
Xenonique 14
Java EE 7 released 2013 Built products on top of a standard platform Transactions, Concurrency, Remote Endpoints, Lifecycle, State, Persistence
Java is a programming language. Java is a virtual machine. Java is a platform.
Xenonique 15
Java EE 7
Xenonique 16
Xenonique
Context & Dependency Injection
• Writing Scala beans • Annotate with Scala @BeanProperty on
POSI (Plain Old Scala Instances) • Ensure compatibility with Java code • @BeanProperty exposes properties to CDI
17
Xenonique
Plain Old Scala Instance
@ApplicationScoped class CashierService { @BeanProperty @Inject() var service: PaymentService = _ def process( acc: Account, amount: BigDecimal): Unit = { service.debit(amount); acc.balance = acc.balance - amount } }
18
Xenonique
CDI Dependent Object
@ApplicationScoped class PaymentService { var message: String = _ def debit(amount: BigDecimal): Unit = { message = s"You paid ${amount}" } } // Note String interpolators
19
Xenonique
CDI Model instance
class Account( var balance: BigDecimal ) // This is a complete class definition! ;-)
20
Xenonique
CDI Scala Gotchas • Companion Objects cannot be used • Case Classes (and obviously Case Objects) – Failure due to creation of multiple static methods
in byte code
• Implicit class parameters • Implicit method parameters • Lazy public vals also fail
21
Xenonique
Building Java EE 7 War Files • Gradle allows developers to build WAR files
very easy and also add customisation • Explicitly include the Scala Library JAR as a
dependency • With SBT, it is harder to create WAR files – Battling between *.scala and *.sbt files
22
Xenonique
Sample Gradle Dependencies
dependencies { providedCompile 'javax:javaee-api:7.0’ compile 'org.scala-lang:scala-library:2.11.2' testCompile 'junit:junit:4.11' testCompile 'org.scalatest:scalatest_2.11:2.2.0’ }
23
Xenonique
CDI Factory #1
trait Maker { def createSample(): Fruit } @ApplicationScoped class FruitFactory { private class CocktailMaker extends Maker { override def createSample():Fruit = new Strawberry } private class FruitSaladMaker extends Maker { override def createSample():Fruit = new Banana } }
24
Xenonique
CDI Factory #2
@ApplicationScoped class FruitFactory { // ... @Produces def generateCocktail(): Maker = new CocktailMaker() @Produces def generateFruitSalad(): Maker = new FruitSaladMaker() }
25
Xenonique
CDI Factory #3
trait Fruit { val price: Double; val name = this.getClass.getSimpleName } case class Apple() extends Fruit { override val price = 0.75 } case class Banana() extends Fruit { override val price = 0.95 } case class Strawberry() extends Fruit { override val price = 2.99 }
26
Xenonique
#1 Collection Of Case Classes
@ApplicationScoped class FruitVendor { def sell( fruit: Fruit with Product with Serializable, quantity: Int): Double = { fruit.price * quantity } }
27
Xenonique
#2 Collection Of Case Classes
@Test def shouldPriceFruitWithQuantity(): Unit = { val fruits = List((Apple,2), (Orange,4), (Banana,5)) for ( (fruit, quantity) <- fruits) { val product = fruitVendor.sell(fruit(), quantity) assertEquals( product, fruit().price * quantity, 0.01 ) } }
28
Xenonique
#3 Collection Of Case Classes Sugaring of Supertype
scala> val list = List( Apple -> 1, Orange -> 4, Banana -> 7 ) list: List[(scala.runtime.AbstractFunction0[ Product with Serializable with Fruit] with Serializable, Int)] = List((Apple,1), (Orange,4), (Banana,7)) // [R]AbstractFunction0.apply() => R // fruit() returns the Fruit mix-in type
29
Xenonique 30
#2 Arquillian: Prefer integration tests over unit tests. You can write Arquillian tests with Scala You cannot yet mix ScalaTest specifications
Xenonique
Writing Arquillian Tests with Scala #1
// HERE WOULD BE THE IDEAL WORLD import org.jboss.arquillian.junit.Arquillian import org.junit.runner.RunWith import org.scalatest.junit. JUnitSuite} import org.scalatest.{FlatSpecLike, Matcher} @RunWith(classOf[Arquillian], classOf[JUnitRunner]) /* ;-) */ class HelloArquillianSpec extends JUnitSuite with FlatSpecLike with Matchers { }
31
Xenonique
Writing Arquillian Tests with Scala #2
// The Reality of the Situation in 2014 @RunWith(classOf[Arquillian]) class HelloArquillianSpec extends JUnitSuite with Matchers { // You can’t use BDD like specificationsL }
32
Xenonique
Writing Arquillian Tests with Scala #3
// Add a companion object, generate a WAR file object HelloArquillianSpec { @Deployment def createDeployment():WebArchive = { ShrinkWrap.create( classOf[WebArchive], "test.war") .addPackage("uk.co.xenonique.digitalone") .addAsLibrary( GradleDependency.resolve(
"org.scala-lang:scala-library:2.11.1") ) .addAsLibrary( GradleDependency.resolve(
"org.scalatest:scalatest_2.11:2.2.0") ) .addAsManifestResource(EmptyAsset.INSTANCE, "beans.xml”) } }
33
Xenonique
Writing Arquillian Tests with Scala #4
// Add a companion object @RunWith(classOf[Arquillian]) class HelloArquillianSpec extends JUnitSuite with Matchers { @Inject var hello: Hello = _ @Test def shouldPrintAPoliteGreeting():Unit = { val msg = hello.hello("JavaOne 2014") // ;-) At least, we can use matchers! (msg) should be ("Hello JavaOne 2014") } }
34
Xenonique 35
#3 Servlets A Java Servlet is a web component managed container. Java Servlets are based on the Java technology, they generate dynamic content, and hence the container that manages them is capable of delivering dynamic content to the web client.
Xenonique
Simplest Json Servlet @WebServlet(Array("/simple")) class SimpleServlet extends HttpServlet { override def doGet(req: HttpServletRequest, resp: HttpServletResponse): Unit = { resp.setContentType("application/json”) val writer = resp.getWriter() writer.println( s""" |{ | "trackTitle": "Two Tribes", | "class": "${this.getClass().getName}", | "date": "${new Date()}" |} """.stripMargin ) } }
36
Xenonique 37
#4 JAX-RS Easy to write in Scala Jackson Annotations, Json4S We demand Json support with seamless Scala support Jackson, especially, FasterXML is extremely helpful https://github.com/FasterXML/jackson-annotations/ For Parsing JSON from text strings, then examine Json4S https://github.com/json4s/json4s
Xenonique
Convert Posis to Json
// How do we convert this POSI to JSON // to seamlessly and easily? ;-/ class Traveller( @BeanProperty var givenName: String, @BeanProperty var familyName: String, @BeanProperty var dateOfBirth: Date , @BeanProperty var docNo: String )
38
Xenonique
Jackson Json Jaxb Annotations
// Look at the Jackson JAX-B project for // inspiration ;-D class Traveller2( @BeanProperty @JsonProperty("givenName") var givenName: String, @BeanProperty @JsonProperty("familyName") var familyName: String, @BeanProperty @JsonProperty("dateOfBirth") var dateOfBirth: Date, @BeanProperty @JsonProperty("documentNo") var docNo: String )
39
Xenonique
Restful Scala JAX-RS Service Endpoint
@Path("/traveller") class TravellerServiceEndpoint { @GET() @Produces(Array(MediaType.APPLICATION_JSON)) def retrieve(): Response = { val cal = Calendar.getInstance() cal.set(1986, Calendar.MAY, 21) val dob = cal.getTime val traveller = new Traveller2("Sam", "Smith", dob, "1234567890") Response.ok(traveller).build() } }
40
Xenonique
Jackson Json Mapping With Provider
@Singleton @Provider @Consumes(Array(MediaType.APPLICATION_JSON, "application/*+json", "text/json")) @Produces(Array(MediaType.APPLICATION_JSON, "application/*+json", "text/json")) class JacksonScalaContextResolver extends JacksonJaxbJsonProvider(JacksonScalaContextResolver.getObjectMapper, JacksonJaxbJsonProvider.DEFAULT_ANNOTATIONS) object JacksonScalaContextResolver { def getObjectMapper: ObjectMapper = { val mapper = new ObjectMapper with ScalaObjectMapper mapper.registerModule(new DefaultScalaModule) mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) mapper.setSerializationInclusion(Include.NON_NULL) mapper } }
41
Xenonique
Case Classes Instances and Jackson Annotations
@JsonIgnoreProperties(Array("databaseId", "computedDeliveryDateTime")) case class Traveller3( @BeanProperty @JsonProperty("givenName") var givenName: String, @BeanProperty @JsonProperty("familyName") var familyName: String, @BeanProperty @JsonProperty("dateOfBirth") var dateOfBirth: Date , @BeanProperty @JsonProperty("documentNo") var docNo: Option[String], @BeanProperty var computedDeliveryDateTime: Date = new Date())
42
Xenonique
Consuming of Json to Scala Case Class Instance #1
@POST() @Consumes(Array(MediaType.APPLICATION_JSON)) def store( traveller: Traveller3): Response = { if ( traveller.getDocNo().isEmpty ) { Response.status( Response.Status.BAD_REQUEST) .entity(ErrorMessage("E199", "Missing document No")) .build() } else { Response.ok().build() } }
43
Xenonique
Case Class #2
case class ErrorMessage( @JsonProperty("id") var id: String, @JsonProperty("error") var text: String) // Renders // { "id": "E199", // "error": "Missing document No" // }
44
Xenonique 45
#5 JSF Easy to write in Scala Conversational, FlowScoped RequestScoped, SessionScoped All types of validation are supported including BeanValidation just like Java
Xenonique
Conversational Scoped Managed Bean
@Named("wizard") @ConversationScoped class RegisterDrivingLicense extends Serializable { @Inject var conversation: Conversation = _; @BeanProperty var title: String = _ @BeanProperty var firstName: String = _ @BeanProperty var lastName: String = _ /* ... */ }
46
Xenonique
Controller Methods
def jumpGettingStarted(): String = { beginConversation() "form1?faces-redirect=true" } def submitPage1(): String = { beginConversation() "form2?faces-redirect=true" }
47
Xenonique
Conversational States
def beginConversation(): Unit = { if (conversation.isTransient()) { conversation.begin() } } def endConversation(): Unit = { if (!conversation.isTransient()) { conversation.end() } }
48
Xenonique
Finish Conversational Scopes
def submitDeclarationPage(): String = { endConversation() if ( !declaration ) { // The declaration was not signed cancelApplication() } else { // Here the form is complete "end?faces-redirect=true" } }
49
Xenonique 50
#6 JMS JMS is straight forward to code with Scala MDB is essentially an asynchronous EJB Tricky part is publishing with JMS 2.0!
Xenonique
JMS with CDI Qualifiers #1
class JMSResourceProducer { @Resource(name = "jms/OrderConnectionFactory") val orderConnFactory: QueueConnectionFactory = _ @Produces @Order @Resource(name = "jms/OrderQueue") val orderQueue: Queue = _ @Produces @Order def createOrderConnection(): QueueConnection = orderConnectionFactory.createQueueConnection() /* ... */ }
51
Xenonique
JMS with CDI Qualifiers #2
class JMSResourceProducer { /* ... */ @Produces @Order def createOrderSession( @Order conn:QueueConnection): QueueSession = conn.createQueueSession( true, Session.AUTO_ACKNOWLEDGE) }
52
Xenonique 53
Xenonique 54
#Conclusion(1) Source code is available now! https://github.com/peterpilgrim/digital-scala-javaone-2014
Xenonique 55
#Conclusion(2) Scala and Java EE 7 integrate well from an Object-Oriented point of view Java EE 8 and Lambda API promise a functional approach. Java EE 7 annotations work in Scala. The ability of Jackson annotations and a singleton provider to seamlessly handle Scala’s case classes is a wonderful addition. Arquillian almost works completely with ScalaTest.
Xenonique 56
#Conclusion(3) WAR files require the runtime Scala Library Decent server configuration using Chef and Puppet can obviate the bundling of the runtime Scala allows developers to avoid Java boilerplate Library writers should prefer to explicitly declare the return types of functions and methods
Xenonique 57
@peter_pilgrim
uk.linkedin.com/in/peterpilgrim
2000/
Xenonique 58
#101 Bonus Information on Scala A Powerful weapon that requires great responsibility Great developers can create apps AM #1: “Interactions and individuals over processes and tools”
Xenonique
How to avoid null pointers in Scala Programming?
val greeting1: Option[String] = Some("AOTB14") val greeting2: Option[String] = None
59
Xenonique
Pattern Matching
def checker(p : Option[String]): String = { p match { case Some(v) => v case _ => "Unexpected" } } checker(greeting1) // "Hello AOTB14" checker(greeting2) // "Unspecified"
60
Xenonique
Scala’s generic immutable list collection type
val list: List[Int] = List(1,2,3,4) list.foreach { x => println(x) } // 1,2,3,4
61
Xenonique
Scala’s option behaves like collection type #2
greeting1.foreach { x => println(s"Work: ${x}" ) } // Work: Hello AOTB14
greeting2.foreach { x => println(s"Work: ${x}" ) } // *** nothing happens ***
62
Xenonique
Read, Evaluate, Print, Loop • Scala, Clojure, Groovy, Kotlin, Ceylon, Fantom All have a interpretative mode • Java JDK does not (yet) have an official REPL (However try out javarepl.com online) • Fingers crossed Project Kulla in JDK 9 http://blog.gmane.org/gmane.comp.java.openjdk.general
63
Xenonique
List of Creative Commons (2.0) photography attributions
https://flic.kr/p/ayqvZp https://www.flickr.com/photos/throughpaintedeyes/ Ryan Seyeau Follow 1000 Faces of Canada # 0084 - Zombie Walk - Explore! Shot during the annual Zombie Walk in Ottawa. https://flic.kr/p/Pp93n https://www.flickr.com/photos/spacesuitcatalyst/ William A. Clark Follow Measurement Measure twice, cut once. https://flic.kr/p/81dXuT https://www.flickr.com/photos/froboy/ Avi Schwab Follow Equipment used for measuring planes of crystals https://flic.kr/p/2QHt7Q https://www.flickr.com/photos/rosefirerising/ rosefirerising Follow Pierre Curie, Piezo-Electroscope
64
Xenonique
List of Creative Commons (2.0) photography attributions
https://www.flickr.com/photos/code_martial/ https://flic.kr/p/7jmU5n Tahir Hashmi Follow Developer Death 10 Programmers and a UX Designer died all of a sudden in a war room situation. They were apparently working too hard. https://www.flickr.com/photos/8268882@N06/ https://flic.kr/p/duwd1M Peter Pilgrim IMG_1481 European JUG leaders meeting in Devoxx 2013 https://www.flickr.com/photos/unicefethiopia/ https://flic.kr/p/dv4ooi UNICEF Ethiopia Follow Hamer mother and child South Omo Zone, SNNPR Hamer mother and child South Omo Zone, SNNPR. ©UNICEF Ethiopia/2005/Getachew
65
Xenonique
List of Creative Commons (2.0) photography attributions
https://www.flickr.com/photos/15216811@N06/ https://flic.kr/p/baULpM N i c o l a Follow Tree - IMG_1242 https://flic.kr/p/dwCQ7t https://www.flickr.com/photos/90585146@N08/ marsmetn tallahassee Follow IDA .. Integro-Differential Analyzer (Sept., 1952) ...item 2.. Richard Dreyfuss: Technology Has 'Killed Time' -- "In geopolitics, the removal of time is fatal." -- "And you will give up, the protection of Republican Democracy." (July 19 2010) ... https://flic.kr/p/6ZDbiZ https://www.flickr.com/photos/ingmar/ Ingmar Zahorsky Follow Traffic Jam Accidents are common on the narrow streets going through the mountains of Nepal. When such an accident occurs, traffic is often halted for up to 3-4 hours. https://flic.kr/p/opvVsg https://www.flickr.com/photos/gregbeatty/ Greg Beatty Follow Three Pillars Nikon D800 16-35MM F4.0 https://flic.kr/p/FAskC https://www.flickr.com/photos/mari1008/ mari_1008 Follow traffic jam -B Date: April,2th Address: Jiangshu Rd,Shanghai,China. Around 8:30 AM today, A little accident on YuYuan Rd and JiangSu Rd caused traffic jam.
66
Xenonique
List of Creative Commons (2.0) photography attributions
https://flic.kr/p/bpss6D https://www.flickr.com/photos/76029035@N02/ Victor1558 Follow Creative_Photoshop_HD_Wallpapers_laba.ws https://flic.kr/p/mLxu3m https://www.flickr.com/photos/astrangelyisolatedplace/ astrangelyisolatedplace Follow Office test #1. Setup fully functional. A rare 1200 no longer in production. Test run soundtracked by the only #vinyl in the office; The Sesame Street Soundtrack - a surprise present by @idinesh #technics #turntable #1200 #ocdv1 via Instagram ift.tt/1hpeUEU https://flic.kr/p/gLPhEk https://www.flickr.com/photos/stevecorey/ Steve Corey Follow Treasure Hunt, a short story (5 images)
67
Xenonique
List of Creative Commons (2.0) photography attributions
https://flic.kr/p/4JcerK https://www.flickr.com/photos/16949884@N00/ Bömmel Follow Ice Crystal Ice is nice https://flic.kr/p/dSsXiZ https://www.flickr.com/photos/jeremyhall/ Jeremy Hall Follow Called to Serve (suit and tie) https://flic.kr/p/3enERy https://www.flickr.com/photos/paolocampioni/ Paolo Campioni Follow scala Scendo (stair case spiral)
68
Xenonique
List of Creative Commons (2.0) photography attributions
https://flic.kr/p/m62gmK https://www.flickr.com/photos/lata/ -p Follow Abstraction I. From my platycerium. (Guide: Voronoi diagram) https://flic.kr/p/6WSFR4 https://www.flickr.com/photos/62337512@N00/ anthony kelly Follow big ben big ben and underground sign https://flic.kr/p/w7qef https://www.flickr.com/photos/cobalt/ cobalt123 Follow All We are Saying... (Thought for a New Year) Peace Pasta from Annie's, with peas, of course. Give Peace A Chance
69