Showing posts with label REST. Show all posts
Showing posts with label REST. Show all posts

Tuesday, March 20, 2018

Lets give Spring the Boot

Hi folks.  It's been a while since I've posted anything here.  Let's just say that life is complicated.

I was inspired to write this based on some recent experiences with Spring Boot.  This is a very powerful technology that relies on Spring and takes it to new and interesting places.  The bottom line is that while there are many ways to structure a system, if we pick one and stick with it we see some real benefits.  Productivity improves, communication between developers is facilitated, and some really cool automation can be brought to bear on the task of building a system.

So what IS Spring Boot?  It's really a few classes and conventions wrapped around Spring that frees the developer from a lot of the grunt work that used to be required.  For instance, the need for xml configuration files has been essentially eliminated.  Can I get an amen?  There is a lot more to it, but why don't we just dig in and create a simple application?

package com.oopuniversity.hellospringboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplicationpublic class App  {
    public static void main(String args[]) {
        SpringApplication.run(App.class, args);    }
}

There you have it.  A complete application which does nearly nothing...  And yet it's really got a lot going on inside of it.  This will actually create an application server listening (by default) on port 8080.

If we run this program we will see output like this:

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.0.0.RELEASE)

2018-03-19 20:08:06.184  INFO 248504 --- [           main] com.oopuniversity.hellospringboot.App    : Starting App on Razer-Laptop with PID 248504 (C:\Users\jd\workspace\basics\hello-spring-boot\build\classes\java\main started by jd in C:\Users\jd\workspace\basics)
2018-03-19 20:08:06.186  INFO 248504 --- [           main] com.oopuniversity.hellospringboot.App    : The following profiles are active: development
2018-03-19 20:08:06.225  INFO 248504 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6a01e23: startup date [Mon Mar 19 20:08:06 EDT 2018]; root of context hierarchy
2018-03-19 20:08:07.349  INFO 248504 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
2018-03-19 20:08:07.386  INFO 248504 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
2018-03-19 20:08:07.386  INFO 248504 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.5.28
2018-03-19 20:08:07.398  INFO 248504 --- [ost-startStop-1] o.a.catalina.core.AprLifecycleListener   : The APR based Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: [C:\Program Files\Java\jdk1.8.0_152\bin;C:\WINDOWS\Sun\Java\bin;C:\WINDOWS\system32;C:\WINDOWS;C:\ProgramData\Oracle\Java\javapath;C:\Program Files (x86)\Razer Chroma SDK\bin;C:\Program Files\Razer Chroma SDK\bin;C:\Program Files (x86)\Intel\iCLS Client\;C:\Program Files\Intel\iCLS Client\;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\Program Files\PuTTY\;C:\ProgramData\chocolatey\bin;c:\bin;c:\bin\flyway-5.0.6;C:\Program Files\MySQL\MYSQL Server 5.7\bin;C:\Program Files\MySQL\MySQL Utilities 1.6\;C:\Program Files\Git\cmd;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Amazon\AWSCLI\;C:\Program Files (x86)\Graphviz2.38\bin;C:\Ruby24-x64\bin;C:\Users\jd\AppData\Local\Microsoft\WindowsApps;C:\Users\jd\apache-maven-3.5.2\bin;;.]
2018-03-19 20:08:07.500  INFO 248504 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2018-03-19 20:08:07.500  INFO 248504 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1277 ms
2018-03-19 20:08:07.606  INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean  : Servlet dispatcherServlet mapped to [/]
2018-03-19 20:08:07.609  INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-03-19 20:08:07.609  INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-03-19 20:08:07.610  INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-03-19 20:08:07.610  INFO 248504 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean   : Mapping filter: 'requestContextFilter' to: [/*]
2018-03-19 20:08:07.898  INFO 248504 --- [           main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for @ControllerAdvice: org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6a01e23: startup date [Mon Mar 19 20:08:06 EDT 2018]; root of context hierarchy
2018-03-19 20:08:07.967  INFO 248504 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-03-19 20:08:07.969  INFO 248504 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-03-19 20:08:07.993  INFO 248504 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-03-19 20:08:07.993  INFO 248504 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-03-19 20:08:08.024  INFO 248504 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-03-19 20:08:08.131  INFO 248504 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2018-03-19 20:08:08.162  INFO 248504 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2018-03-19 20:08:08.164  INFO 248504 --- [           main] com.oopuniversity.hellospringboot.App    : Started App in 2.244 seconds (JVM running for 2.621)

That's really am amazing amount of output for what appears to be a one-liner, isn't it?  One of the beautiful things about Spring Boot (and Spring in general) is that it is well documented internally and tells you what it's doing.  Perhaps more importantly it's really good about telling you what went wrong, which is pretty much an inevitability.

Since no URIs are defined, it won't actually serve up any pages as written, but you can tell it's doing at least something by hitting it with a browser.

Spring Boot is incredibly well suited to today's world of cloud-native applications built as micro-services.  An application such as this really doesn't need anything more than a functional JVM to be spun up as one instance or a hundred.  Everything it really requires to run can be bundled into a single .jar file and distributed where needed.  There's no more hassle with deploying application servers and the attendant configuration and devops challenges.

Let's add some functionality to this little program, so that it actually does a task for us.  We're going to build a RESTful calculator.  If you aren't familiar with RESTful services you can go look up what I'm talking about, but in short RESTful services are stateless web-based services that accept parameters in a URL and return usable responses to whoever calls them.  This allows for amazing levels of integration, and every task can be built using the technology best suited for it.

Since this is really just a technology demonstrator, I will not be building any of this using best practices for project layout and the like.  All of that is ultimately important but unnecessary for the purpose of this post.

Let's start with adding two numbers.  As this will be a RESTful service, everything needed to perform the math must be specified on the URL.  I will define it like this:

/add/number1/number2

That way, all I should really need to do to add 1 and 1 is call "http://localhost:8080/add/1/1"

Doing this is really very easy.  First, I need to inform Spring Boot that I want to serve up RESTful responses.  In the real world I'd create a new class (or several of them) for this purpose, but for now I'll just add it to the same little program.



That's straightforward enough.  Now we have to put in the code to do the math:

First we will need to add a couple of supporting imports:



And then we're ready to craft a working service:



The '@RequestMapping' annotation sets up a URI with embedded variables that will be used to invoke our new service.  The @PathVariable annotation ties the embedded variables to the parameter list for our method.

Believe it or not, that's all we need to get this working:



As you can imagine, it's as straightforward as can be to extend this to additional operations.

I will leave it as an exercise for the reader to add more operations to this.  It's very straightforward and you really shouldn't have any problems doing so.

That's about it for now.  Have fun!




Sunday, June 5, 2016

JSON? What is this, Friday the 13th?

JSON stands for "JavaScript Object Notation", and it is nothing more than a standardized format for pushing object properties around in text format.  This is handy for many purposes, especially for transmitting objects over networks.  I can create objects in Java, convert them to JSON, and then read them in Javascript on a browser.  That's all kinds of handy.

There are plenty of tools for working with JSON,  I personally like Jackson from fasterxml.com.  This package provides a great deal of functionality in an easy to use form.  It's not the only JSON library out there, not by a long shot:  But it's simple, quick, and widely used.  It's also one of the core technologies selected for the 'DropWizard' framework, which I'll be talking about in another post.

Have an object and want to make a JSON representation?  Then ObjectMapper is the tool for you:

First of all, let's create a simple object called 'Person'.  For the sake of simplicity, we'll assume that all we care about is the name.

public class Person {
    private String givenName;
    private String surName;

    // This object has to be a Bean, which means it needs a no-argument constructor    

    public Person() {}

    public Person(String surName, String givenName) {
        this.surName = surName;
        this.givenName = givenName;
    }

    public String getGivenName() {
        return givenName;
    }

    public void setGivenName(String givenName) {
        this.givenName = givenName;
    }

    public String getSurName() {
        return surName;
    }

    public void setSurName(String surName) {
        this.surName = surName;
    }

    @Override    public String toString() {
        return "Person{" +
                "givenName='" + givenName + '\'' +
                ", surName='" + surName + '\'' +
                '}';
    }
}

This import statement is important, and of course you'll have to get the .jar file to support it.  I would suggest just using maven to deal with that.

import com.fasterxml.jackson.databind.ObjectMapper;

...
    ObjectMapper objectMapper = new ObjectMapper();
    Person p = new Person("Doe", "John");
    String jsonRepresentation = objectMapper.writeValueAsString(p);
    System.out.println(jsonRepresentation);

Going back the other way is even easier:

Person p2 = objectMapper.readValue(jsonRepresentation, Person.class);
This works very well within a single project of course.  Let's say you  need to persist your objects to disk for later use.  Well, the JSON representation gives you an excellent way to do this without running into the various issues that straight Java object serialization can raise.  Your files will be human-readable, human-editable, and they're much less likely to become unusable because you changed an object definition.  What's not to love about that?
In fact, reading and writing files is an extremely simple operation with Jackson.  The ObjectMapper does most of the hard lifting for you and turns basic (or not so basic) persistence into one line operations.  If you wanted to take that Person object up above and stash it in a file on your hard drive for later use all you'd need to do is this:
objectMapper.writeValue(new File("JohnDoe.txt"), p);
Reversing the operation is almost as easy:  You just need to use one special little piece of syntax to tell ObjectMapper what kind of object you are creating:

Person p2 = objectMapper.readValue(new File("JohnDoe.txt"), Person.class);
We've basically now recreated what we did in the first couple of examples, but we're able to run one example today and the next one tomorrow after restarting the computer if we want, since instead of just sitting in a String in our program's memory the important information is now sitting on your hard drive.  The file looks like this, by the way:
{"givenName":"John","surName":"Doe"}
JSON is also great for transmitting data over networks.  In fact, if you take a look at RESTful services (which I will visit in a future post) JSON is a standard way of communicating with them.  You don't even have to care what language the remote system uses.  Just so long as you both agree on the set of properties to be sent, the other end could be written in C, .NET, JavaScript (hey, look at what the 'J' stand for in the first place) or any other language.  Maybe the other end is also written in Java, but it was developed by someone else who doesn't have access to your library with your definition of Person.  That's perfectly OK, they can roll their own very easily and so long as the properties in your JSON are all supported everything will just work:
Let's pretend we are on the other side now, and the file created above was sent to us.  We want to bring the data into our system using our home grown "AnotherPerson" class.  For demonstration purposes, the class is exactly the same as the "Person" class above, except for the property names.  So it contains code like this:
public class AnotherPersonNoAnnotations {
    private String firstName;
    private String lastName;

    // This object has to be a Bean, which means it needs a no-argument constructor    

public AnotherPersonNoAnnotations() {}

    public AnotherPersonNoAnnotations(String lastName, String firstName) {
        this.lastName = lastName;
        this.firstName = firstName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    ...

When we try to read the object, we do this:
AnotherPerson p = objectMapper.readValue(new File("JohnDoe.txt"), AnotherPerson.class);
And it fails spectacularly!
Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "givenName" (class com.oopuniversity.json.model.AnotherPersonNoAnnotations), not marked as ignorable (2 known properties: "lastName", "firstName"])
 at [Source: {"givenName":"John","surName":"Doe"}; line: 1, column: 15] (through reference chain: com.oopuniversity.json.model.AnotherPersonNoAnnotations["givenName"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
...
The actual error will be followed by a whole bunch more stuff, but the important information is right at the top.  And notice:  This is an extremely useful error message.  It tells you exactly what went wrong and why.  It's an "UnrecognizedPropertyException" which means exactly what it says:  Jackson did not recognize a property it found.  Then it flat out tells you that 'givenName' is the problem.  It also tells you which properties it can recognize.  Then to top it off it shows you the exact JSON it was trying to read.  I wish all libraries were this good at telling us what went wrong.
So now we know that our object supports "lastName" and "firstName" but the data contains "givenName" and "surName".  Fixing this is quite simple.
Not to worry, even though we have different names for our properties we'll be fine.  This is far from an uncommon situation and Jackson has it handled.  All we need to do is add a couple of  'annotations' to our code.  Annotations are a clever addition that was made to Java years ago.  Classes, properties and methods can be annotated in order to add new behaviors.  In this case, we'll use them to inform Jackson that we are expecting different field names.  We change our 'AnotherPerson' class so that the declarations look like this:
public class AnotherPerson {
    @JsonProperty("givenName")
    private String firstName;
    @JsonProperty("surName")
    private String lastName;
I think that's pretty self-explanatory.  We're telling Jackson that when it's processing our file, it should think of our 'firstName' field as though it was called 'givenName', and of course the same thing applies to 'lastName' and 'surName'.  These annotations affect both reading and writing and now our class, while it uses our preferred variable names internally, looks to the outside world exactly like the Person class listed above.
Now our attempt to read the file works beautifully:
AnotherPerson{firstName='John', lastName='Doe'}
This is not all there is to say about  JSON processing with Jackson, but it is certainly a good start.  I'm sure I'll be talking about it more in posts to come.  I mentioned but did not talk about using this stuff to communicate between running systems (via RESTful services) and that's a key area that many developers will want to understand.
A code repository with working examples can be found here.
https://github.com/OOPUniversity/JSON_Basics