Java: warning qui se transforme en ClassCastException ou la joie des génériques (generics) et du type erasure

java8 jackson2-logo-only

 

Type erasure ça vous parle?

Peut-être mais ça reste néanmoins une notion un peu floue ou trop abstraite!

Pourtant ce n'est pas que de la théorie!

Et si on pratique tout cela?

Nous allons voir par l'exemple comment un warning levé par le "compilo" devient une exception à l'exécution.

Oui, ça compile bien mais au Run une exception est levée!

L'introduction des génériques était une des évolutions marquantes en java 5.

Mais à regarder de près quelque chose de pas très net traînait surtout depuis l'arrivée de java 8!

Passons à la pratique pour conclure ensuite sur les concepts abordés.

 

ETAPE 1. Configurer les dépendences

        <properties>
	 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	 <java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
		 <groupId>org.springframework.boot</groupId>
		 <artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
				
	</dependencies>

	

	<build>
	  <plugins>
		<plugin>
	 	  <groupId>org.springframework.boot</groupId>
		  <artifactId>spring-boot-maven-plugin</artifactId>				
		</plugin>
			
	  </plugins>
	</build>
pom

 

ETAPE 2Classe POJO

public class User {

	private Long id;

	private String firstname;

	private String lastname;

	private String email;

//...getters setters omis
POJO

 

ETAPE 3Test unitaire

Voici le code entier du test Junit 4:

import java.io.IOException;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

public class TestErasureTests {

  final static String JSON_USERS = "[
     {\"id\":1,\"firstname\":\"a\",\"lastname\":\"A\",\"email\":\"a@aa.com\"},
     {\"id\":2,\"firstname\":\"b\",\"lastname\":\"B\",\"email\":\"b@bb.com\"}
     ]";

  @Test /*(expected = ClassCastException.class)*/
  public void testErasureKO() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<User> list1 = mapper.readValue(JSON_USERS, List.class);
    Assert.assertNotNull(list1);
    User userFound = list1.get(0); //CastException erasure en evidence
    Assert.assertNotNull(userFound);
  }
  @Test
  public void testErasureOK() throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<User> list2 = mapper.reader()
                             .forType(new TypeReference<List<User>>() {})
                             .readValue(JSON_USERS);
    final User userA = list2.get(0);
    Assert.assertEquals("a", userA.getFirstname());
    Assert.assertEquals("A", userA.getLastname());
    Assert.assertEquals("a@aa.com", userA.getEmail());
  }
}
test junit

 

Explication.

Le premier nommé testErasureKO met en évidence l'exception ClassCastException liée justement au concept type erasure.

Notez bien l'attribut de @Test qui est, provisoirement, commenté.

Ainsi, le run via la commande mvn test permet d'afficher l'exception en question.

Si vous le dé-commentez, le test passe au vert!

Dans ce premier test, la ligne utile à lire est celle commentée avec "CastException erasure en évidence".

Le second test illustre juste ce qu'il faudrait faire pour gérer correctement le type générique lors du mapping jackson.

 

ETAPE 4CONCLUSION

Les génériques en java est une évolution majeure dans java 5, le soucis étant qu'en runtime la jvm perd le type réel des objets conteneurs (list par exemple).

Le type erasure est justement, au niveau de l'exécution,  une perte d'information bien connue du compilateur.

Pour remédier par exemple lors du mapping d'objets conteneurs, une attention particulière est exigée.

Avec le premier test Junit, on palpe la notion "type erasure" et on découvre la joie des génériques.

@Enjoy,

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.