Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Friday, December 20, 2013

An Annotation Nightmare

@XmlElementWrapper(name="orders")
@XmlJavaTypeAdapter(OrderJaxbAdapter.class)
@XmlElements({
   @XmlElement(name="order_2",type=Order2.class),
   @XmlElement(name="old_order",type=OldOrder.class)
})
@JsonIgnore
@JsonProperty
@NotNull
@ManyToMany
@Fetch(FetchMode.SUBSELECT)
@JoinTable(
    name = "customer_order",
    joinColumns = {
        @JoinColumn(name = "customer_id", referencedColumnName = "id")
    },
    inverseJoinColumns = {
        @JoinColumn(name = "order_id", referencedColumnName = "id")
    }
)
private List orders;

Wait. What? Is this really what we have come to? I can't even see the damn property under this bloat. How did this happen? Yeah ok - we had to get rid of the old xml configuration horror somehow. But this? This is even WORSE. This class is supposed to be a goddamn pojo with a bunch of properties. Short and concise, easy to read. I, as a reader of this cass, am not interested at all how the database table is joining customers to orders. I'm neither interested how its being serialized. This is just implementation details. Reading this class, i am living in an object world and i want to know what data and behaviour the object has. Not more, not less. I don't care about column names, fetchtypes or json serialization for the moment. And i don't want to read, change or recompile this class for the sake of a tablename change. I don't want to add another annotation for storing this entity in a mongoDB neither. The entity should not have responsibility for these details. We are not only violating the Single Responsibility Principle here, we are doing a f****** responsibility party.

Ok ok, enough of the rage. How do we deal with this issue? Some duplicate the entity for various layers with different annotation purposes. They map the entity onto the next layers related entity using an automated mapper like Dozer. Some even write that mapping themselves. But this is by no means a solution. It is just replacing one code smell with another one: Duplication.

So please, focus on frameworks that don't force you to clutter your code. jOOQ is a nice solution to map database records to entities without annotations. Also, hibernate allows you to define your mappings in XML.

Private Field Injection


@Inject
private MyService myService

This is used quite often, while it shouldn't even be possible. The myService field is private, thus it's inaccessible from outside the class. Nevertheless it's possible and people do it. In reality it is a hack. The DI-framework sets the field using reflections doing setAccessible(true). You don't want hacks in your code, do you? Lets have a look at the alternatives:

Setter Injection
Well, at least its better than the private field injection, since its using a public method instead of hacking a private field. But still, ask yourself this: 'Is this class even supposed to live without the injected value?' Because if it's not, there is no reason what so ever for the class to get constructed without an instance of MyService. You want to implement this constraint on the class level and inside the constructor, not on the framework level.

Constructor Injection
This is usually the way to go. It allows you to
  • make the field immutable (there is usually no need to change it).
  • implement the constraint, that the class is not instantiatable without a given MyService in the right place.
Of course it means that you cannot inject by annotation. But why would you want to? The class doesn't need to know, if it gets injections by a DI-Container or a Factory Class. It should not know anything of this. No @Autowired, no @Qualifier. All it needs to know is its own behaviour. Everything else should be handled outside of the class.
One could use a configuration class or file for the actual injection.

A DI-Container is a usefull tool that helps you wire your classes together. Use it for this purpose, but don't let it dictate your code. Uncle Bob wrote a great post where he explained how to use DI-Frameworks without having them dictate your code.

@RunWith(SpringJUnit4ClassRunner.class) in UnitTests

Why would you need this in unittests? Because it is automatically generated by your IDE/app template? No! You want to test the behaviour of a class, living in isolation in unittests. Not if the DI-Conainer is injecting a fields accordingly. Just inject yourself in a setup method. No DI-Container needed. By the way, all this testrunner does is these 3 lines of code.

private TestContextManager testContextManager;
//..
this.testContextManager = new TestContextManager(getClass());
this.testContextManager.prepareTestInstance(this);

They are not worth blocking your only TestRunner slot. You want to keep it free for something like parameterized @RunWith(JUnitParamsRunner.class) or concurrency @RunWith(ConcurrentJunitRunner.class) tests.

@Override

Really, my IDE already knows if i am correctly overriding a method. To me, its just clutter.

@SuppressWarnings

... Don't even get me started

tl;dr
Annotations have become more harmful than helpful these days. We should get back to pojos and focus on keeping our code as clutterless and framework-agnostic as possible to make it more readable and reuseable. Don't let frameworks dictate your codebases, since they should be exchangable tools. Beware of what a class should know, and what not. Some annotations are useful, most aren't.

@DevNull({
 @SuppressWarnings
 @Autowired, 
 @Inject, 
 @Override,  
 @XmlElementWrapper,
 @XmlJavaTypeAdapter,
 @XmlElement,
 @JsonIgnore,
 @JsonProperty,
 @ManyToMany,
 @Fetch,
 @JoinTable
})

Tuesday, October 15, 2013

Boost your development speed

I'm really pragmatic on this. To go faster, you need to avoid the things that slow you down. These blockers may vary from developer to developer, but some are pretty common. In this post i will elaborate on the more common ones. Before i do so i want to remind you that to improve, we might need to unlearn in the first place.
Tip: Sometimes, the greatest achievement in improving is to successfully unlearn.

Are you using your Mouse?

Don't let your mouse slow you down. If you are not using all of your fingers typing, you might want to stop reading here and go over to a typewriting course. The following recommendation also assumes that you are using a feature rich editor like vim or an ide. Every single time you move your hand over to your mouse for a click there is a keyboard shortcut for the exact action that you are not aware of, or not used to. You want to learn these. It's really not that hard,  you'll get used to it faster than you'd think. Just begin by putting your mouse over to the other (or wrong) side of your keyboard. You're now forcing yourself to think every time you want to click. When this happens, remember to think of a possible solution using your keyboard. Don't know any? Ask your friends or search the internet (yes, you can use your mouse for that). BUT: Do not use your mouse for what ever action you wanted to perform. After following these simple rules for a few days, you'll notice how irrelevant your mouse has become. If you start feeling comfortable using your keyboard only, you could even try some sessions with your mouse plugged out. Mastering your keyboard will significantly boost your development speed.
Tip: You could print out a list of your IDEs shortcuts and use it as a cheatsheet

Reduce the Time debugging

Debugging costs an awful lot. It's not rare that we end up hunting a bug for hours or even days. Quite often we engage multiple co-workers to solve it. This is really not a scenario we want to be in, since its not only expensive, but also depressing. How can we avoid such a scenario? Pretty easy. Just separate the software into pieces that work in isolation, and write automated tests that cover the components behaviour. This way, we can easily distinguish the component the bug is actually sitting in, and the debugging will become a cinch. The better the tests, the easier to find the bug. However, you wont write good tests, if the system that you are testing is already done and working. You'll assume that there is no additional value of writing thoughtout tests, when it's already working. Overcome this dilemma by writing your tests BEFORE the implementation. As a side effect, this will also help you coding in many ways. You want to treat your tests as first class citizens and as what they are - at least as important as your implementation. Think of a blacksmith who's casting metal into a mold. What would be more important for him. The mold, or the first sculpture coming out of it? You know the answer. And guess what... the tests are your mold. I don't care what you call it. TDD, BDD or whatever. Just automate tests to cover your softwares behaviour, write them before the implementation, and treat them as what they are - at least as important as your implementation.
Tip: When using TDD, you want to use a shortcut to quickly navigate between the test and its implementation. I've bound it to Alt+T


Reduce the Time reading code

I can't stress this enough: You spend more time reading code than writing code. Believe it or not, while implementing a new feature or solving a bug, you repeatedly read code. You read code before you start writing new code, you read code multiple times inbetween writing code, and you read code after you have written it. Reading a 50 line method is pretty time consuming. Thus you want to make reading as easy and smooth as possible. Write self explanatory code with good names and short methods. And Don't Repeat Yourself. Who wants to read anything twice? Invest some time on this, and it will pay off.

Improve your search skills

This is an important one. A searchengine has become the most important development tool. It is even more important than your ide. You can do anything without your ide if you can find out how, but you cannot do anything with your ide if you dont know how. You are probably googling regularely, so it's worth improving. Improve your searchterms. Anticipate helpful words like 'how to' or 'problem'. Try different variants and quote important words and sentences. If you keep getting bad results of a common subject or website, filter them out using a preceeding minus. Here are some examples:
  • while c -do -c++
  • SomeException -helpme.com
  • How to "clean code"
If you keep getting out-dated information, limit your search to the last month/year. This can easily be done in the search options. On stackoverflow, do not always read the first post since its usually a question and code thats not working. Scroll down to the answers with the most upvotes. They are worth reading. Bookmark the sites/docs that you are using regularely. You don't want to search them over and over again. Also, consider code search engines (Examples here and here).


Focus & Calm

You want to get into and keep a good focus when working on a task. Get into your flow and do not allow disruptions. Several disruptions can easily cost you an hour or two each day. Use headphones in louder environments, and communicate that you'll be available for questions a little later. Focus requires a clear mind. Make sure you don't have to remember too much stuff. You don't want to be afraid of forgetting things. If you can feel the fear to forget, write that thing down - so you can forget. Also, don't work on too many different tasks/projects at the same time. One is perfect, two is ok. More is probably just slowing you down. I've happened to work on 7 different projects a single day. It's really really dragging from you. Also, stay calm even in the most stressful situation. Huddling just slows you down even more.

Invest in Hardware

Hardware is cheap, workhours are not. Good hardware will save lots of time in the long term. An SSD that makes you boot within seconds and loads everything real quick, saves at least 10 minutes a day which is 40 hours a year. Same goes with ram and cpu of course. Also, screensize really matters. Choose a large monitor to be able to see everything without resizing/scrolling windows/panels. I personally feel comfortable with ~27". You can speed up many tasks using two monitors also. Web development would be such a task for example.
Tip: 16:9 is standard nowadays but not quite optimal for coding. The higher the screen, the more lines of code you see. Try a 16:10 instead.

Optimize your Workflow, Question your Tools

It depends on what you are working on, but the goal stays the same. You want the most lean workflow and you will constantly have to reevaluate and improve it. For example: If you are working on a Java Webapp, you want to be able to quickly get feedback without redeploying. You can do this by using a class-reloader like spring-loaded or JRebel, or use the Play Framework which does not require redeployments at all due to its architecture. You could also question the language. Is there something else than java that could be more appropriate? Automate everything: testing, building, deployment, notifications. Consider rapid prototyping if you are in the early stages of a project.


Monday, August 12, 2013

spring-data-rest in Action

What is spring-data-rest?

spring-data-rest, a recent addition to the spring-data project, is a framework that helps you expose your entities directly as RESTful webservice endpoints. Unlike rails, grails or roo it does not generate any code achieving this goal. spring data-rest supports JPA, MongoDB, JSR-303 validation, HAL and many more. It is really innovative and lets you setup your RESTful webservice within minutes. In this example i'll give you a short overview of what spring-data-rest is capable of.

Initial Configuration 

I'm gonna use the new Servlet 3 Java Web Configuration instead of an ancient web.xml. Nothing really special here.

public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class<?>[]{AppConfiguration.class};
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[]{WebConfiguration.class};
    }

    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
}
WebAppInitializer.java on github

I am initializing hibernate as my database abstraction layer in the AppConfiguration class. I'm using an embedded database (hsql), since i want to keep this showcase simple stupid. Still, nothing special here.

@Configuration
@EnableJpaRepositories
@EnableTransactionManagement
public class AppConfiguration {

    @Bean
    public DataSource dataSource() {
        EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
        return builder.setType(EmbeddedDatabaseType.HSQL).build();
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
        HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
        vendorAdapter.setDatabase(Database.HSQL);
        vendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setJpaVendorAdapter(vendorAdapter);
        factory.setPackagesToScan(getClass().getPackage().getName());
        factory.setDataSource(dataSource());

        return factory;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager();
    }
}
AppConfiguration.java on github

Now to the application servlet configuration: WebConfiguration

@Configuration
public class WebConfiguration extends RepositoryRestMvcConfiguration {
}
WebConfiguration.java on github

Oh, well thats a bit short isnt it? Not a single line of code required for a complete setup. This is a really nice application of the convention over configuration paradigm. We can now start creating spring-data-jpa repositories and they will be exposed as RESTful resources automatically. And we can still add custom configuration to the WebConfiguration class later if needed.

The Initialization was really short and easy. We didn't have to code anything special. The only thing we did was setting up a database connection and hibernate, which is obviously inevitable. Now, that we have setup our "REST Servlet" and persistence, lets move on to the application itself, starting with the model.

The Model

I'll keep it really simple creating only two related entities.
@Entity
public class Book {

    @Id
    private String isbn;

    private String title;

    private String language;

    @ManyToMany
    private List<Author> authors;

}
Book.java on github

@Entity
public class Author {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE)
    private Integer id;

    private String name;

    @ManyToMany(mappedBy = "authors")
    private List<Book> books;

}
Author.java on github

To finally make the entities persistent and exposed as a RESTful webservice, we need spring-data repositories. A repository is basically a DAO. It offers CRUD functionality for our entities. spring-data takes away most of your programming effort creating such repositories. We just have to define an empty interface, spring-data does everything else out of the box. Still, it is easily customizable thanks to its design by convention over configuration!

The Actual Repositories


@RestResource(path = "books", rel = "books")
public interface BookRepository extends PagingAndSortingRepository<Book, Long> {
}
BookRepository.java on github


@RestResource(path = "authors", rel = "authors")
public interface AuthorRepository extends PagingAndSortingRepository<Author, Integer> {
}
AuthorRepository.java on github

Again, there is nearly no code needed. Even the @RestResource annotation could be left out. But if i did, the path and rel would be named after the entity, which i dont want. A REST resource that contains multiple children should be named plural though.

Accessing The Result

Our RESTful webservice is now ready for deployment. Once run, it lists all available resources on the root, so you can navigate from there.

GET http://localhost:8080/
{
  "links" : [ {
    "rel" : "books",
    "href" : "http://localhost:8080/books"
  }, {
    "rel" : "authors",
    "href" : "http://localhost:8080/authors"
  } ],
  "content" : [ ]
}

Fine! Now lets create an author and a book.

POST http://localhost:8080/authors
{"name":"Uncle Bob"}

Response
201 Created
Location: http://localhost:8080/authors/1
PUT http://localhost:8080/books/0132350882
{
  "title": "Clean Code",
  "authors": [
      {
          "rel": "authors",
          "href": "http://localhost:8080/authors/1"
      }
  ]
}

Response
201 Created
Noticed how i used PUT to create the book? This is because its id is the actual isbn. I have to tell the server which isbn to use since he cant guess it. I used POST for the author as his id is just an incremental number that is generated automatically. Also, i used a link to connect both, the book (/books/0132350882) and the author (/authors/1). This is basically what hypermedia is all about: Links are used for navigation and relations between entities.

Now, lets see if the book was created accordingly.

GET http://localhost:8080/books
{
  "links" : [ ],
  "content" : [ {
    "links" : [ {
      "rel" : "books.Book.authors",
      "href" : "http://localhost:8080/books/0132350882/authors"
    }, {
      "rel" : "self",
      "href" : "http://localhost:8080/books/0132350882"
    } ],
    "title" : "Clean Code"
  } ],
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 1
  }
}

Fine!

Here is an Integration Test, following these steps automatically. It is also available in the example on github.

public class BookApiIT {

    private final RestTemplate restTemplate = new RestTemplate();

    private final String authorsUrl = "http://localhost:8080/authors";
    private final String booksUrl = "http://localhost:8080/books";

    @Test
    public void testCreateBookWithAuthor() throws Exception {
        final URI authorUri = restTemplate.postForLocation(authorsUrl, sampleAuthor()); // create Author

        final URI bookUri = new URI(booksUrl + "/" + sampleBookIsbn);
        restTemplate.put(bookUri, sampleBook(authorUri.toString())); // create Book linked to Author

        Resource<Book> book = getBook(bookUri);
        assertNotNull(book);

        final URI authorsOfBookUri = new URI(book.getLink("books.Book.authors").getHref());
        Resource<List<Resource<Author>>> authors = getAuthors(authorsOfBookUri);
        assertNotNull(authors.getContent());
        assertFalse(authors.getContent().isEmpty()); // check if /books/0132350882/authors contains an author
    }

    private String sampleAuthor() {
        return "{\"name\":\"Robert C. Martin\"}";
    }

    private final String sampleBookIsbn = "0132350882";

    private String sampleBook(String authorUrl) {
        return "{\"title\":\"Clean Code\",\"authors\":[{\"rel\":\"authors\",\"href\":\"" + authorUrl + "\"}]}";
    }

    private Resource<Book> getBook(URI uri) {
        return restTemplate.exchange(uri, HttpMethod.GET, null, new ParameterizedTypeReference<Resource<Book>>() {
        }).getBody();
    }

    private Resource<List<Resource<Author>>> getAuthors(URI uri) {
        return restTemplate.exchange(uri, HttpMethod.GET, null, new ParameterizedTypeReference<Resource<List<Resource<Author>>>>() {
        }).getBody();
    }
}
BookApiIT.java on github

Conclusion

We have created a complete RESTful webservice without much coding effort. We just defined our entities and database connection. spring-data-rest stated that everything else is just boilerplate, and i agree.

To consume the webservices manually, consider the rest-shell. It is a command-shell making the navigation in your webservice as easy and fun as it could be. Here is a screenshot:


The complete example is available on my github
https://github.com/gregorriegler/babdev-spring/tree/master/spring-data-rest
https://github.com/gregorriegler/babdev-spring


Friday, August 2, 2013

Good Bye Redeployment. spring-loaded, an Opensource Classreloader

Redeem yourself from hot deployments and OutOfMemoryException. spring-loaded is an opensource classreloader and a promising alternative to JRebel. It does not offer as many features as JRebel does, and it does not support any framework just yet. Nevertheless, its a great tool that can save the time you are waiting for that servletcontainer to restart again.

What it can do:
  • add/modify/delete methods/fields/constructors
  • modify annotations on types/methods/fields/constructors
  • add/remove/change values in enum types
What it cant:
  • support framework specific changes like Spring MVC @RequestMappings
  • change log configuration on the fly
It is not getting the attention that it deserves, so give it a try.

Just download from github already, and add the following to your JVM parameters:
java -javaagent:<pathTo>/springloaded-{VERSION}.jar -noverify

Sunday, July 21, 2013

Spring MVC - @RequestBody and @ResponseBody demystified

In this post i want to dig into spring mvc a little, revealing what happens behind the scenes when a request is converted to your parameter object and vice versa. Before we start, i want to explain the purpose of these annotations.

What are @RequestBody and @ResponseBody for?


They are annotations of the spring mvc framework and can be used in a controller to implement smart object serialization and deserialization. They help you avoid boilerplate code by extracting the logic of messageconversion and making it an aspect. Other than that they help you support multiple formats for a single REST resource without duplication of code. If you annotate a method with @ResponseBody, spring will try to convert its return value and write it to the http response automatically. If you annotate a methods parameter with @RequestBody, spring will try to convert the content of the incoming request body to your parameter object on the fly.

Here is an example

@Controller
@RequestMapping(value = "/bookcase")
public class BookCaseController {

    private BookCase bookCase;

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public BookCase getBookCase() {
        return this.bookCase;
    }

    @RequestMapping(method = RequestMethod.PUT)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void setBookCase(@RequestBody BookCase bookCase) {
        this.bookCase = bookCase;
    }

}

So what is Spring doing behind the scenes when we are using those Annotations?


Depending on your configuration, spring has a list of HttpMessageConverters registered in the background. A HttpMessageConverters responsibility is to convert the request body to a specific class and back to the response body again, depending on a predefined mime type. Every time an issued request is hitting a @RequestBody or @ResponseBody annotation spring loops through all registered HttpMessageConverters seeking for the first that fits the given mime type and class and then uses it for the actual conversion.

How can i add a custom HttpMessageConverter?


By adding @EnableWebMvc respectively <mvc:annotation-driven />, spring registers a bunch of predefined messageconverters for JSON/XML and so on. You can add a custom converter like the following

@Configuration
@EnableWebMvc
@ComponentScan
public class WebConfiguration extends WebMvcConfigurerAdapter {

    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> httpMessageConverters) {
        httpMessageConverters.add(new BookCaseMessageConverter(new MediaType("text", "csv")));
    }
}

In this example i've written a converter that handles the conversion of a BookCase, which is basically a List of Books. The converter is able to convert csv content to a BookCase and vice versa. I used opencsv to parse the text.

Here is the model

public class Book {

    private String isbn;

    private String title;

    public Book(String isbn, String title) {
        this.isbn = isbn;
        this.title = title;
    }

    // ...
}

public class BookCase extends ArrayList<Book> {

    public BookCase() {
    }

    public BookCase(Collection<? extends Book> c) {
        super(c);
    }
}

and the actual converter

public class BookCaseMessageConverter extends AbstractHttpMessageConverter<BookCase> {

    public BookCaseMessageConverter() {
    }

    public BookCaseMessageConverter(MediaType supportedMediaType) {
        super(supportedMediaType);
    }

    public BookCaseMessageConverter(MediaType... supportedMediaTypes) {
        super(supportedMediaTypes);
    }

    @Override
    protected boolean supports(Class<?> clazz) {
        return BookCase.class.equals(clazz);
    }

    @Override
    protected BookCase readInternal(Class<? extends BookCase> clazz, HttpInputMessage httpInputMessage) throws IOException, HttpMessageNotReadableException {
        CSVReader reader = new CSVReader(new InputStreamReader(httpInputMessage.getBody()));
        List<String[]> rows = reader.readAll();
        BookCase bookCase = new BookCase();
        for (String[] row : rows) {
            bookCase.add(new Book(row[0], row[1]));
        }
        return bookCase;
    }

    @Override
    protected void writeInternal(BookCase books, HttpOutputMessage httpOutputMessage) throws IOException, HttpMessageNotWritableException {
        CSVWriter writer = new CSVWriter(new OutputStreamWriter(httpOutputMessage.getBody()));
        for (Book book : books) {
            writer.writeNext(new String[]{book.getIsbn(), book.getTitle()});
        }
        writer.close();
    }
}

The Result 

We can now issue text/csv requests to our Resource along with application/json and xml which are basically supported out of the box.

1.)
PUT /bookcase
Content-Type: text/csv
"123","Spring in Action"
"456","Clean Code"

Response
204 No Content
2.)
GET /bookcase
Accept: text/csv

Response
200 OK
"123","Spring in Action"
"456","Clean Code"

Thanks to the design of spring mvc, which is following the single responsibility principle, our controller stays thin. We don't have to add a single line if we want to support new media types.

The complete example is available on my github

Friday, April 26, 2013

Standalone Java Webapp made easy with Maven

Introduction

As you may already know, creating a war archive and deploying it on a preinstalled Servlet Container is not the only way running a Java webapp, since you can also embed the Web-Server in the application itself. Sometimes such artifacts are delivered as standalone executable programs that can be easily started and stopped in the commandline and even run as a service in the background. Maybe you should also consider producing your app this way and benefit from its huge advantages:
  • No preinstalled Webserver/Servlet Container required that would take additional maintenance.
  • Easy Cross-Platform. Same artifact can of course be run on any System.
  • Complete Standalone Software
Apache Sonar is a great Example of such Software. It uses an embedded Jetty Server and creates an embedded H2 Database for persistence that can be replaced in configuration. As you can see here they prepared startup scripts for any Platform that execute the actual StartServer class.

Embedded Tomcat

In my tutorial ill use an embedded Tomcat as a Servlet Container. So we want to add the Maven dependencies first.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<!-- embedded Tomcat -->
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-core</artifactId>
    <version>7.0.37</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-logging-log4j</artifactId>
    <version>7.0.37</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat.embed</groupId>
    <artifactId>tomcat-embed-jasper</artifactId>
    <version>7.0.37</version>
</dependency>

We can use them now to create a StartServer class

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
public final class StartServer {

    private StartServer() {
    }

    public static void main(String[] args) throws Exception {
        
        // We will set the basedir Systemproperty accordingly when running the Program
        // Actually the mavenplugin appassembler will do this for us
        String basedir = System.getProperty("basedir");
        String webappLocation = new File(basedir + "/webapp").getAbsolutePath();
        int port = 8080;

        Tomcat tomcat = new Tomcat();
        tomcat.setPort(port);
        tomcat.addWebapp("/", webappLocation);
        tomcat.start();
        tomcat.getServer().await();
    }
}

Exploded War

Now we need to make an exploded war in our "target" directory. I choose to create a folder inside "target" that holds the application as a whole including bin files, configuration and the webapp itself. This makes it easy to transport the complete app to another machine.
  • src/...
  • target/myapp/bin
  • target/myapp/conf
  • target/myapp/webapp
Ill include the maven-war-plugin to create the exploded war.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <id>war-exploded</id>
            <phase>package</phase>
            <goals>
                <goal>exploded</goal>
            </goals>
            <configuration>
                <webappDirectory>${project.build.directory}/myapp/webapp</webappDirectory>
                <archiveClasses>true</archiveClasses>
            </configuration>
        </execution>
    </executions>
</plugin>

If you run mvn clean package right now you should get your webapp compiled into target/myapp/webapp

Startup Scripts

Finally we need startup Scripts to actually run our application. We need a shell script for unix Systems and a bat file for Windows. The Appassembler maven plugin comes in handy here. It is a very thoughtout plugin that creates exactly what we need and even sets the basedir Systemproperty. I'll configure it to use our exploded webapp and StartServer class.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>appassembler-maven-plugin</artifactId>
    <version>1.3</version>
    <configuration>
        <assembleDirectory>${project.build.directory}/myapp</assembleDirectory>
        <repositoryLayout>flat</repositoryLayout>
        <repositoryName>webapp/WEB-INF/lib</repositoryName>
        <generateRepository>false</generateRepository>
        <copyConfigurationDirectory>true</copyConfigurationDirectory>
        <configurationDirectory>conf</configurationDirectory>
        <programs>
            <program>
                <mainClass>com.myapp.StartServer</mainClass>
                <name>myapp</name>
            </program>
        </programs>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>assemble</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Done. Appassembler now creates executable scripts for all platforms inside the target/myapp/bin directory. You could even put configuration files into src/main/config that would be copied into target/myapp/conf automatically by the plugin.

Result


If we run mvn clean package now we get a completely transportable standalone webapp in our target directory!

Wednesday, April 10, 2013

I18n of JPA Entities

Sadly the support for i18n for Entities in JPA is actually very poor to non-existent. There's just basically no out of the box solution provided by Hibernate & Co, although i18n is a feature that could be considered mandatory for a powerful ORM Framework. If you take a look at PHP for example Doctrine supports i18n very well. So besides some really unpopular i18n extensions on forums/github you are basically on your own.

So how do you do it?

There isn't really a general solution to achieve i18n. There are many different ways and you have to choose which is actually best for you. If you do have a relatively small amount of data and ordering by translations is not necessary you can store "keys" in your tables that are being translated by Spring i18n for example. Spring i18n could store the translations in separate property files. Since you wont have to worry about performance, this is a very easy way to achieve i18n.

But lets say you have lots of data, and you need to order it on the database side. With such requirements you are better off storing translations inside your database tables. While there are guides, and also an opensource framework on the internet that implement i18n with one centralized translation-table that holds all translations i highly recommend not to follow that idea. The problem with this solution is, that you will have to add one more join for every field that has to be translated, whereas multiple joins for a single table with lots of data can easily become a performanceissue.
Its better to follow the approach to create a separate translation-table for every entity. This means that you would have one entity containing simple data, and another one containing only the fields that require translation. Like so:

This schema is pretty normalized and you only have a single join on fetching an entity, while you can still order appropriate.

Your entities would look like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Entity
public class Book {

    @Id
    private int isbn;

    private String author;

    private Date releaseDate;

    @OneToMany
    @JoinColumn(name = "isbn")
    private List<BookTranslation> translations;

    // constructor, getters and setters -...

}

and that

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Entity
public class BookTranslation implements Serializable {

    @Id
    private int isbn;

    @Id
    private String locale;

    private String title;

    private String description;

    // constructor, getters and setters -...

}

You could then fetch a book with its translations with:

select b from Book b join fetch b.translations bt where bt.locale = 'de';

If you cannot accept your ServiceLayer to deliver two entities for every Book only because of translations, i suggest you to implement some DTO like this BookTO which holds all values.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
public class BookTO {

    private int isbn;

    private String author;

    private Date releaseDate;

    private String title;

    private String description;

}

You'd just need to map the values of Book and BookTranslation to BookTO within your ServiceLayer and also return BookTO instead of Book in your ServiceLayer.

This solution might not always be the most appropriate, but it definitely comes in handy sometimes.