Categories
Programming Projects

List of Quirks when using Spring Framework and Kotlin

I’m not used to the JVM environment. Usually I use NodeJS, Ruby with Rails or PHP with Laravel. But after awhile, I find these dynamic programming environment quite problematic, especially on a large project. Rails is simply too magical, it is dark magic. Sure, it have a nice syntax, but debugging them is quite a hell and no type safety means you really need to unit test your software. PHP and Laravel is not that bad actually, but when the things that makes it nice came from statically typed language, like type hints and IoC container, why not just use a true statically typed language? NodeJS have quite a lot of things. You can have type safety with typescript. You probably can get an IoC container… if you want to use them. But the whole NodeJS environment is way too immature and changes too quickly making it feels quite brittle. Update a package and the whole thing could collapse. Not too mention typescript support really depends on the library maintainer. Its the same case for flowtype too. Except I had worse luck with it.

So, when you want to use a statically typed programming language to make a web application, two things came to mind: C# and Java. Other languages are too not-mainstream enough. With C#, you have .NET MVC and with Java, you have Spring, Jersey and Play framework. The open source version of .NET which is .NET Core is simply too immature. So whats left is Java. Java is quite tedious, but luckily, we have Kotlin, which is another programming language running on top of the JVM with very high interoperability with Java. In the choice of framework, Play framework utilize Akka which is way too different than conventional application. Jersey is actually quite nice, but it does not have a built in integration with other things. Spring is the most famous of them all, so its not that hard to choose, its just that it could be overwhelming.

First of all, what is Spring framework? You need to get this right real quick, because the libraries built around it is quite a lot. At its core, the Spring framework by itself is only an IoC container. Spring MVC is a web framework that have the Model-View-Controller architecture that we want. Spring Data is an umbrella project for data access related things and among those is Spring Data JPA which provides integration with JPA (Java Persistence API) which is a java specification for ORM (Object Relational Model). Spring Data JPA utilizes Hibernate which is a JPA implementation.

Now do you see what I mean by overwhelming? All of these libraries are configured by declaring a Configurer bean. A bean is basically a fancy way of saying class/object with specific structure. You can also configure through XML, but that is old school technique which result is a huge mess of XML. The new way is too declare a Configurer class and configure it with code. In general you’ll probably use a ConfigurerAdapter instead, because Configurer is an interface and you don’t want to configure everything. But still, that is a lot of configuration. Which is why they created Spring Boot, another project which is basically a collection of configurations of these libraries. Spring Boot will detect if you include these library and will automatically apply a default reasonable configuration. ‘reasonable’ does not mean convenient, or in some sense even reasonable. I guess a better word is ‘compatible’ or ‘safe’. Still, it is too invaluable that you probably should google ‘Spring Boot’ instead of ‘Spring Framework’. But what if you want to adjust some parameters of some library? Well, it could be that Spring Boot have already enabled the use of configuration files. Which by default is usually application.properties. But you can also use YAML. I’m not exactly sure the file name for that. But what are the settings? Here comes the problem with Spring framework in general: the only documentation is its user guide/reference and those references are very long. That, or you go through the source code of Spring Boot or the respective library, which are Java code, which are very long.

Once you get through those long and tedious readings, assuming nothing goes wrong, you get the ability to:

  • Create an MVC controller by annotating arbitrary class, with the base path and so on.
  • Declare a a bean which is an interface that extends CrudRepository<Model, Int> where Model is your arbitrary POJO (Plain Old Java Object) that have certain annotations that declare it as a model. And inject it to your arbitrary other bean (like your controller), gaining a free implementation of your interface that interface with your database.
  • Include liquibase in your gradle, then just declare your migration in resources/db.changelog/db.changelog-master.yaml.
  • Ability to map http body to arbitrary object, effectively parsing JSON request to a POJO, with a single annotation.
  • Return a POJO from your controller method, and it will automatically convert it to JSON.
  • Annotate your POJO with java.validation annotations and annotate your POJO controller parameters with @Valid and it will throw error if the JSON send does not validate.
  • Ability to annotate your bean method with a security expression, and it will throw error if it does not pass.
  • Java’s plain simple and conventional generic and inheritance model.
  • Probably other things too.

If that sounds quite magical, well it is. Maybe too magical, that if somethings goes wrong, you don’t know what happen. Good thing its all mainly Java code, so you got nice IDE support for debugging. But its a whole lot of Java code. A whole lot.

Of course, its not all good. Some of it is quite bad actually. The template is JSP which I’m not a big fan off. You can’t easily rollback your database. I use it mainly for a rest controller. Unfortunately in that regard, Jersey brings more things out of the box. When a validation error happen, it does not report it as a nice JSON. Jersey does that nicely. When a resource is not found and so it fails to bind the resource as parameter, it simply pass an empty resource. Jersey return a nice 404. And of course, when something goes wrong, I’ll take a day or two to find the problem. So here is a list of problem/quicks I found so far. I’ll probably update it as I found more issues.

It is asking for a password, some csrf validation error? And CORS issues.

By default, the spring boot configured spring security will ask for password, which is randomly generated. CSRF protection is enabled, not really useful for REST. Also, CORS will need to be allowed. So I used these config to overcome those issues.


import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.web.cors.CorsConfiguration
import org.springframework.web.cors.CorsConfigurationSource
import org.springframework.web.cors.UrlBasedCorsConfigurationSource
import javax.inject.Named

/**
 * Created by amirul on 31/05/2017.
 */
@Configuration
@EnableWebSecurity
class WebSecurityConfig: WebSecurityConfigurerAdapter() {
	override fun configure(http: HttpSecurity) {
		http
			.cors().and()
			.csrf().disable()
			.authorizeRequests()
			.anyRequest().permitAll().and()
	}

	@Bean
	fun corsConfigurationSource(): CorsConfigurationSource {
		val configuration = CorsConfiguration();
		configuration.allowedOrigins = listOf("*");
		configuration.allowedMethods = listOf("GET","POST" ,"PATCH");
		configuration.allowedHeaders = listOf("*");
		val source = UrlBasedCorsConfigurationSource();
		source.registerCorsConfiguration("/**", configuration);
		return source;
	}
}

Model Validation does not work with kotlin.

If you use a data class with the constructor arguments, make sure you annotate the field instead of the getter/setter with something like @field:NotBlank.

In a one to many column relationship, on save, the child’s foreign key is not set, and I’ve specify it in database as non-null, so it will crash.

In a a JoinColumn annotation, make sure you specify nullable = false, like this @JoinColumn(name= "parent_id", nullable = false)

In a one to many relationship, if I remove the child item from the array from the parent object and save the parent, the removed child is not removed in the database.

In the @OneToMany annotation, make sure to set orphanRemoval to true.

I’m getting `org.hibernate.HibernateException: A collection with cascade=”all-delete-orphan” was no longer referenced by the owning entity instance:`.

Yea… the collection in the entity is pretty special. So you can’t just assign them and hope the complex datamapper technique to work. So don’t replace the collection object itself. Call clear and addAll instead.

I’m getting `org.hibernate.AnnotationException: Collection has neither generic type or OneToMany.targetEntity()`.

Try not using Kotlin’s immutable List. Which is the default list. Use MutableList instead. Yeah, I know Hibernate does not play well with immutable data types at all.

Leave a Reply

Your email address will not be published.