Pokazywanie postów oznaczonych etykietą maven. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą maven. Pokaż wszystkie posty

piątek, 26 stycznia 2018

Type safe Java DTOs in Angular with Maven

Introduction

New Angular, as opposed to "old" Angular.JS, uses TypeScript (https://www.typescriptlang.org/). Among others, TS usage allows for a static type checking, a language feature that can prove very useful on the backend / frontend border (namely - REST API level). With a TypeScript interface / class definition for each and every DTO (Java class sent thru API), errors in usage are easily discovered at the compilation stage, well before the code reaches testing.

But how to get TS definitions for all DTOs easily, automatically, without boring process of converting Java to TypeScript? Well, if your build uses good old Maven, your're lucky ;-) There is a plugin that properly configured will output .d.ts file for all of the DTOs. Let me show you how to configure the plugin for a simple Angular application.

Maven configuration

First, we need to configure the plugin in the pom.xml of your application. Fragment may look as follows:
It simply binds the plugin's generate goal to process-classes phase, configuring by the way that:
  • Java enumerations will be mapped to TypeScript string enum (requires TypeScript 2.4)
  • plugin will consider all classes conforming to com.example.**.**Dto
  • namespace in which all of the types will be stored is yournamespace
  • output will be stored in the src/main/webapp/app/dto-definitions.d.ts file (standard Maven web app layout)
  • the output will be global (in a declared namespace, not separate module)

Angular usage

OK, so we have a .ts.d file generated, how to use it now in the Angular application? First, you need to make TypeScript compiler aware of the typings. This differs between frontend builds. In my example, I use grunt with grunt-ts plugin for TypeScript compilation. Therefore, example looks as follows:
Now, once TS compiler is aware of the namespace and contained types (interfaces actually as per configuration), rest is simple. any type can be imported in a following way:
import MyClassDto = yournamespace.MyClassDto;

Tips and tricks

Duplicated and nested Java classes

The example is really minimal and simplified. There are a lot of corner cases that will require additional configuration (or black magic ;-) ) to resolve. My favourite ones are nested classes and duplicated class names.
The first one is problematic as "$" can't be part of the class name in the TypeScript - so Outer$Nester as per Java standard won't work. What can we do? Well, my solution is to rename the class to take simple form of OuterNested.
The second one is problematic as we store all classes in one module - so duplicates from different Java packages will land in the same module - and that's a name clash. What to do then? Well, I simply join duplicated class name with last part of the package declaration. Maybe it doesn't look perfect, but in limited number of duplicated cases is just works ;-)
But how to enable such conversions for the plugin? Let's just configure a customTypeNamingFunction that transforms the name as it comes from Java into TypeScript name. Simple example may look as follows:

Fully-qualified TypeScript names

What about configuring the plugin to output Java types as fully qualified TypeScript types? After all, namespace is similar to package in this regard. Well, don't do that. Why? Because of the type ordering. Plugin and compiler will understand classes in a single namespace - that is order classes referencing other classes. But this does not work for separate packages. If you have (and you certainly do) a Java class that references another Java class in other package, the plugin may output namespace with referenced classes later than the namespace with class referring. As a result, TypeScript compilation will fail as the required type will not be found. Sorry, TS ain't Java ;-) 

czwartek, 13 lipca 2017

[memo] purging broken JARs from Maven repository

Ever encountered dreaded "java.util.zip.ZipException: invalid LOC header (bad signature)" while building a Maven project? If yes, it means that Maven (somehow) downloaded a broken JAR into your repository. There is not much that can be done besides purging all of the "broken" JARs from the repository.

Two options are possible:

  • delete whole Maven repository - which means downloading all of the JARs, of all projects (possibly few gigs) again (!!)
  • delete only offending JARs - list can be obtained for example by issuing following command:
find  /home/me/.m2/repository/ -name "*jar" | xargs -L 1 zip -T | grep error | grep invalid

 Both options, well, suck :-) Fortunately there is a way to purge all of the JARs from local repository that pertain to only one project. It's provided by the dependency Maven plugin. Just issue
mvn dependency:purge-local-repository
and it's done. NEAT!

piątek, 5 maja 2017

[memo] Accessing files in a web application

Sometimes the easiest things are also the easiest to miss (or to forget :-) ). Therefore, in order to have this once and for all in one place - the quickest guide how to access files in a servlet environment (Spring Boot application in my case).

1. Classpath resource

A file that is present in a classpath (typically /WEB-INF/classes, /WEB-INF/lib).
Can be anything, most probably a configuration file that is packed with WAR during package preparation stage. In case of good old Maven - all of the resources (by default src/main/resources) will end up in the classpath. Access - via context class loader.
For example:

2. Web resource 

All of the web application files - including static content (images, styles, html, ...) and files that are loaded into classpath (JARs from /WEB-INF/lib etc.) can be accessed this way. The only requirement is the presence of a ServletContext. 
PRO TIP: In a Spring application, the ServletContext can be simply autowired into a service requiring it. 
For example: 
As a last word - be __very__ cautious when planning to use ServletContext.getRealPath(). Why? Just take a look here: http://stackoverflow.com/questions/12160639/what-does-servletcontext-getrealpath-mean-and-when-should-i-use-it

poniedziałek, 19 marca 2012

33rd Degree - the first day

Fresh impressions right after the first day of the conference (in case someone's not familiar with - 33degree).

First general talk by Raffi Krikorian of Twitter, focused on their move away from RoR to a JVM-based solution. What's more important - not purely Java but Scala as well! I'm no Ruby expert so I learnt some baffling things about it, like one thread per Ruby process model and incredibly faulty GC ;) All in all, his final thought was that RoR is one of the most productive environment for web apps, but not suited to scale. On the other hand, once your product needs to scale and perform you probably have all the money needed to rewrite it.
As a side note - who'd guess few years ago that Java will be perceived as a key tool to achieve better performance? :)

Next two talks - Ken Sipe's "Complexity of Complexity" and Venkat Subramaniam's
"Pointy haired bosses and pragmatic programmers: Facts and Fallacies of Software Development" were typical "generic", entertaining talks as encountered on each and every conference. I don't mean to say the talks were bad, not at all! I personally fancy such presentation, not only filled with geek-jokes and funny slides but also sharing general wisdom stemming from experience in the software development business. It's sometimes akin to looking at a "old scar", like first project that was "overarchitectured" or filled with unnecessary design patterns, just because developers have recently learned them (let's refactor to factory! everything! [diabolic laugh]). Simply put - I enjoyed them but I can't say I learnt a lot.

Next it became harder, as conference split on 4 tracks and I had to blindly choose what to attend. Retrospectively, my picks were 50/50, just as the calculus of probability would say.

"Build Trust in Your Build to Deployment Flow!" was disappointing. I expected something about DevOps/Continuous Deployment and got "Artifactory" feature walk-on. It has some advantages as compared to other artifact repositories (like Maven's Nexus), but it'd not call it DevOps-centric. Unless I'd like to attract some attention by using a trendy buzzword ;)

Sadek Drobi's "Non blocking, composable reactive web programming with Iteratees" was a good, technical demonstration of some Scala's Play capabilities. And those are definitely impressive! Unfortunately presenter assumed participants' deep knowledge of Scala, so from time to time I had problems catching up.

The last presentation was "import continuous.delivery." by Toomas Römer (of ZeroTurnaround). Next attempt in my "quest for holy DevOps". As his predecessor Toomas focused on presenting a product of his company - LiveRebel. However this time I was able to see how it can be nicely integrated within semi-automatic build/deployment/promotion flow. Good job ZeroTurnaround!


Two lessons learned today:
1. Worth to take a deeper look at the Scala, even though ugly Pascal-like syntax :) There are some very interesting ideas behind the language and it's "web arm" - Play.
2. ZeroTurnaround products can sweeten DevOps implementation a bit. Functionally the same can be achieved with a bunch of shell scripts and cron jobs, but why bother? ;)

środa, 3 czerwca 2009

Maven2 production profiles- follow up

Quick follow up - simple example of POM with build profiles for different environments. Nothing especial - just to show how to insert profiles and group properties.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>pl.jwach.examples</groupId>
<artifactId>example</artifactId>
<packaging>jar</packaging>
<version>0.1.0</version>

<dependencies>
...
</dependencies>
<build>

<finalName>${project.artifactId}-${build.env}-${project.version}</finalName>

<plugins>
...
</plugins>

<resources>
<!-- FILTERED -->
<resource>
<directory>src/main/resources/default</directory>
<filtering>true</filtering>
<excludes>
<exclude>**/lib/*.jar</exclude>
<exclude>**/*.someFiles</exclude>
</excludes>
</resource>
<!-- NOT FILTERED -->
<resource>
<directory>src/main/resources/external</directory>
<filtering>false</filtering>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
<!-- DEFAULT FILTERS -->
<filters>
<filter>src/main/filters/default/config.properties</filter>
</filters>
</build>

<!-- Filters do not have to show the src/main -->
<profiles>
<profile>
<id>preprod-env</id>
<properties>
<build.env>preprod-env</build.env>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<filters>
<filter>src/main/filters/preprod-env/config.properties</filter>
</filters>
</build>
</profile>
<profile>
<id>prod-env</id>
<properties>
<build.env>prod-env</build.env>
</properties>
<activation>
<activeByDefault>false</activeByDefault>
</activation>
<build>
<filters>
<filter>src/main/filters/prod-env/config.properties</filter>
</filters>
</build>
</profile>
</profiles>
</project>

As you can see, all profiles are disabled by default. This is because common configuration with custom properties for local deployment are collected in default profile, as stated in build section of the POM. When additional profile is activated, properties from new filter will override properties from default. Thanks to such solution we can minimize number of disjoint properties and build development product version without any extra effort.

wtorek, 2 czerwca 2009

Maven2 for production development

As many Java devs, I regard Maven2 as a great build tool. After accepting sacrifices of "convention over configuration" approach and getting used to usage of plugins (goals), Maven2 speeds up building/testing/deploying a lot. Yet, it's far more potent than simply "define dependencies - build - package" flow. Authors proudly declare M2 to be "software management tool" and I think I could support such statement (in some parts at least).

Particularly, this post is about M2 build profiles. Declared in POM (or global settings.xml file) profiles can alter project build cycle. They can be active by default (see "activeByDefault" node) or activated by -P command-line switch. Profiles offer unique opportunity - creating versions for different deployment environments totally painless! To achieve this, one can define in each profile:

  • resources to be included. For example, if each environment has different server count, you can provide different configuration files. Or if servers run different hardware/software, you can for example feed them with different JNI libs.
  • sources to be complied. This is useful in example when distributing different debug versions (instrumented/pure on QA/production)
  • Filters! This is one of the simplest and best features. In my case I have to deal with many pre-production environments. Most of them are configured alike,but with different IPs, ports and external services (JNDI, DB pools, RESTs...). But those are properties that can be tokenized and set during filtering, without any additional efforts.
  • build plugins - but having different build steps for different environments seems a bit crazy :)

I should add one useful note - define custom "build env name" property for each profile and include it in final artifact name, just like:

<finalName>${project.artifactId}-${build.env}-${project.version}</finalName>

This will help you maintain ready artifact for your environments.