# Import CSV (Adapter) Spécifique

**URL:** <https://community.simplicite.io/t/import-csv-adapter-specifique/2843>\
**Category:** Support\
**Tags:** v4-0\
**Created:** [December 23, 2020, 9:58am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843 "2020-12-23T09:58:01Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sofiane94](https://community.simplicite.io/letter_avatar_proxy/v4/letter/s/b3f665/32.png) [@Sofiane94](https://community.simplicite.io/u/Sofiane94)\
**Post date:** [December 23, 2020, 9:58am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/1 "2020-12-23T09:58:01Z")

</div>

Bonjour à tous,  
J’espère que vous allez bien,  
J’ai rencontre une difficulté sur simplicité, je voudrais créer un adapter CSV spécifique qui va importer un excel renseignant 3 Business Object dans ma BD. pour cela j’ai créer un adapter spécifique dans Operation -\> Adapter, voici le code :

```java
package com.simplicite.adapters.Factur_projetDD;

import java.util.*;
import com.simplicite.util.*;
import com.simplicite.util.integration.*;

import com.simplicite.util.tools.*;

/**
 * Adapter InvEvtCSVAdapter
 */
public class InvEvtCSVAdapter extends CSVLineBasedAdapter {
	private static final long serialVersionUID = 1L;
	private ObjectDB exampleObject = getGrant().getTmpObject("contrat");

	// Good practice : use specific exception class
	private static class InvEvtCSVAdapterException extends Exception{
		public InvEvtCSVAdapterException(String message){
			super(message);
		
		}
	}
	

	
	@Override
	public String processValues(long lineNumber, String[] values){	
		// Good practice: handle errors with exceptions		
		try{
			// add some logs to the .log file (added in the imports supervisor object)
			appendLog("=== Processing line #"+lineNumber+" : "+Arrays.toString(values));
			processWithExceptions(lineNumber, values);
		}
		catch(InvEvtCSVAdapterException e){
			// add some logs to the .err file (added in the imports supervisor object)
			appendError("=== Error with line #"+lineNumber+" : "+Arrays.toString(values));
			appendError(e);

			// change import status to impact the supervisor object
			setStatus(SystemXML.SUPERVISOR_STATUS_IMPORT_ERROR);
		}

		// returned String gets added to a XML subsequently imported.
		// in this case we do not append anything to XML subsequently imported,
		// as we directly create the objects instead
		return null; 
	}

	public void postProcess(){
		appendLog("End Process with status "+getStatus());
		// to generate a subsequently imported XML, call super.postProcess()
		// doing so will add a closing <simplicite> tag
	}

	public void processWithExceptions(long lineNumber, String[] values) throws InvEvtCSVAdapterException{
		String createMsg;
		synchronized(exampleObject){
			exampleObject.resetValues(true);
		exampleObject.setFieldValue("numContrat", values[0]);
		exampleObject.setFieldValue("typeContrat", values[1]);
		
			createMsg = exampleObject.create();
		}
		if(!Tool.isEmpty(createMsg)){
			throw new InvEvtCSVAdapterException(createMsg);
		}
	}

}

```

J’ai l’erreur Adapter :

```auto
Adapter error: null

```

quand j’essaye d’importer un exemple de csv avec uniquement un Business object et 2 object field (numContrat et typeContrat)

J’utilise l’adapter grace à l’external object ImportXML, voici mes question svp :

1. Est t-il la bonne façon de procéder ?
2. Vaut t-il le coup de créer une interface custom plus user-friendly pour utiliser l’adapter spécifique ?
3. Si oui, ça sera quoi le workflow de développement ?

Je vous remercie d’avance, et vous souhaitant de bonnes fêtes de fin d’année à tous

---

<div class="post-metadata">

**Author:** ![david](https://community.simplicite.io/user_avatar/community.simplicite.io/david/32/5703_2.png) [@david](https://community.simplicite.io/u/david)\
**Post date:** [December 23, 2020, 10:13am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/2 "2020-12-23T10:13:26Z")

</div>

Bonjour

`Adapter error: null` =\> Vous avez visiblement un “null pointer exception” non catché qui se produit quelque part dans votre code =\> ajoutez des traces, des blocs `try/catch`, etc. ou, si vous le pouvez, mettez vous en remote debug depuis un IDE (cf [https://vimeo.com/475908811](https://vimeo.com/475908811)).

Pour ce qui est de l’interface d’appel de l’adapter, oui l’interface utilisateur “standard” c’est la page d’import XML avec sélection de l’adapter mais rien ne vous empêche d’ajouter une page specifique = un “objet externe” (dans le vocabulaire Simplicité, cf. [https://docs.simplicite.io/documentation/01-core/externalobject-code-examples.md#responsive](https://docs.simplicite.io/documentation/01-core/externalobject-code-examples.md#responsive)) ou d’invoquer l’import via l’adapter via une action (avec paramètre fichier) d’un objet métier, etc. en fonction de ce qui conviendra le mieux en termes d’UX

---

<div class="post-metadata">

**Author:** ![Sofiane94](https://community.simplicite.io/letter_avatar_proxy/v4/letter/s/b3f665/32.png) [@Sofiane94](https://community.simplicite.io/u/Sofiane94)\
**Post date:** [December 23, 2020, 11:23am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/3 "2020-12-23T11:23:36Z")

</div>

Merci pour votre retour,  
Effectivement, j’ai déplacé le `exampleObject = getGrant().getTmpObject("Contrat");` à la fonction ```  
processValues  
ça donne :

```auto
	@Override
	public String processValues(long lineNumber, String[] values){	
		// Good practice: handle errors with exceptions		
		try{
			exampleObject = getGrant().getTmpObject("Contrat");
	
			// add some logs to the .log file (added in the imports supervisor object)
			appendLog("=== Processing line #"+lineNumber+" : "+Arrays.toString(values));
			processWithExceptions(lineNumber, values);
		}
		catch(InvEvtCSVAdapterException e){
			// add some logs to the .err file (added in the imports supervisor object)
			appendError("=== Error with line #"+lineNumber+" : "+Arrays.toString(values));
			appendError(e);

			// change import status to impact the supervisor object
			setStatus(SystemXML.SUPERVISOR_STATUS_IMPORT_ERROR);
		}

		// returned String gets added to a XML subsequently imported.
		// in this case we do not append anything to XML subsequently imported,
		// as we directly create the objects instead
		return null; 
	}

```

et ça marche, sauf qu’il ne fait pas un update automatiquement quand je charge un csv avec des enregistrement déjà existants, il crée des doublant (l’objet possède 1 clé fonctionnelle ).

Avez vous une idée svp ?  
Merci d’avance

---

<div class="post-metadata">

**Author:** ![david](https://community.simplicite.io/user_avatar/community.simplicite.io/david/32/5703_2.png) [@david](https://community.simplicite.io/u/david)\
**Post date:** [December 23, 2020, 11:40am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/4 "2020-12-23T11:40:03Z")

</div>

Vous devez implémenter la logique de “create or update”:

1. `search` si un record existe sur la base des clés fonctionnelles
2. si oui =\> `getForUpdate` avec le row ID trouvé
3. si non =\> `getForCreate`
4. `validateAndSave`

Genre comme ça : [https://gist.github.com/dazoulay-simplicite/ee17577dc228babcd405b0fed165f80f](https://gist.github.com/dazoulay-simplicite/ee17577dc228babcd405b0fed165f80f)

---

<div class="post-metadata">

**Author:** ![Sofiane94](https://community.simplicite.io/letter_avatar_proxy/v4/letter/s/b3f665/32.png) [@Sofiane94](https://community.simplicite.io/u/Sofiane94)\
**Post date:** [December 28, 2020, 9:28am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/5 "2020-12-28T09:28:33Z")

</div>

Merci pour les précision et l’exemple, j’ai fini par implémenter l’import.

---

<div class="post-metadata">

**Author:** ![scampano](https://community.simplicite.io/user_avatar/community.simplicite.io/scampano/32/10010_2.png) [@scampano](https://community.simplicite.io/u/scampano)\
**Post date:** [December 28, 2020, 9:37am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/6 "2020-12-28T09:37:14Z")

</div>

Bonjour,

Je me permets d’ajouter qu’il n’est pas optimisé de faire le `getGrant().getTmpObject("Contrat");` dans le hook `processValues` qui est appelé à chaque ligne du CSV, vous recréez l’objet à chaque ligne. Dans [l’exemple sur lequel vous vous êtes basé](https://community.simplicite.io/t/csv-adapter-example/2110) cette opération est faite dans le hook `preProcess`.

Le nullpointer que vous obteniez vient du fait que vous avez essayé de faire cette opération lors de l’initialisation de la classe, ce qui n’est pas possible puisque `getGrant()` n’est pas statique et dépend de l’utilisateur. Si c’est une erreur de compréhension et non d’inattention, ne pas approfondir ces sujets purement Java risque d’être problématique. ;)

---

<div class="post-metadata">

**Author:** ![Sofiane94](https://community.simplicite.io/letter_avatar_proxy/v4/letter/s/b3f665/32.png) [@Sofiane94](https://community.simplicite.io/u/Sofiane94)\
**Post date:** [January 6, 2021, 1:19pm UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/7 "2021-01-06T13:19:57Z")

</div>

Bonjour @scampano ,  
Merci pour votre retour, j’ai beau essayé d’implementer le getGrant() dans le preprocess mais cela ne marche pas, voici mon code qui ne fonctionne pas, à l’import rien ne se passe et aucun log, peux tu faire des suggestions s’il te plait ? (cela marche bien quand je mets les getGrant() dans le processValues)

```auto
package com.simplicite.adapters.Factur_projetDD;

import java.util.*;
import com.simplicite.util.*;
import com.simplicite.util.integration.*;

import com.simplicite.util.tools.*;

import com.simplicite.util.tools.JSONTool;
import org.json.JSONObject;

/**
 * Adapter InvEvtCSVAdapter
 */
public class InvEvtCSVAdapter extends CSVLineBasedAdapter {
	private static final long serialVersionUID = 1L;
	private ObjectDB contratBo ;
	private ObjectDB chefprojetBo ;
	private ObjectDB projetBo ;
	private ObjectDB factureBo ;
	
	// Good practice : use specific exception class
	private static class InvEvtCSVAdapterException extends Exception{
		public InvEvtCSVAdapterException(String message){
			super(message);
		
		}
	}
	
	public String preProcess(){
			// set CSV separator
			setSeparator(';'); 
			contratBo = getGrant().getTmpObject("Contrat");
			chefprojetBo = getGrant().getTmpObject("ChefProjet");
			projetBo = getGrant().getTmpObject("Projet");
			factureBo = getGrant().getTmpObject("Facture");
	
			// to generate a subsequently imported XML, call super.preProcess()
			// doing so will add a starting <simplicite> tag
			return null;
		}
		
	@Override
	public String processValues(long lineNumber, String[] values){	
		// Good practice: handle errors with exceptions		
		
		
		try{
			// add some logs to the .log file (added in the imports supervisor object)
			appendLog("=== Processing line #"+lineNumber+" : "+Arrays.toString(values));
			
		
		if (lineNumber>1) // skip header
			processWithExceptions(lineNumber, values);
		}
		catch(InvEvtCSVAdapterException e){
			// add some logs to the .err file (added in the imports supervisor object)
			appendError("=== Error with line #"+lineNumber+" : "+Arrays.toString(values));
			appendError(e);

			// change import status to impact the supervisor object
			setStatus(SystemXML.SUPERVISOR_STATUS_IMPORT_ERROR);
		}

		// returned String gets added to a XML subsequently imported.
		// in this case we do not append anything to XML subsequently imported,
		// as we directly create the objects instead
		return null; 
	}

	public void processWithExceptions(long lineNumber, String[] values) throws InvEvtCSVAdapterException{
    
    	synchronized(factureBo){	
	    	synchronized(projetBo){	
		    	synchronized(chefprojetBo){	
					synchronized(contratBo){
						
					try {
					//Create BO Tool for each BO
					BusinessObjectTool contratBot = new BusinessObjectTool(contratBo); // or contratBo.getTool();
					BusinessObjectTool chefprojetBot = new BusinessObjectTool(chefprojetBo);
					BusinessObjectTool projetBot = new BusinessObjectTool(projetBo);
					BusinessObjectTool factureBot = new BusinessObjectTool(factureBo);
				
					//Start Processing 
					
					//Processing for "Projet"
					List<String[]> rs = projetBot.search(new JSONObject()
					.put("numero_projet", values[3]));
				
					if (rs.size() == 1) // 1 found = update
						projetBo.setValues(rs.get(0), true);	
					
					else if (rs.size() == 0) // 0 found => create
						{
						projetBo.resetValues(true); 
						
						//Processing for "contrat"
						rs = contratBot.search(new JSONObject().put("numContrat", values[0]));
					
						if (rs.size() == 1) // 1 found = update
						contratBo.setValues(rs.get(0), true);
						
						else if (rs.size() == 0) // 0 found => create
						contratBo.resetValues(true); //
					
						else // Should never happen if search is done using all functional keys
						throw new Exception(rs.size() + " contact records found");
						
						contratBo.setFieldValue("numContrat", values[0]);
						contratBo.setFieldValue("typeContrat", values[7]);	  
						contratBot.validateAndSave();
						
						//Processing for "ChefProjet"
						rs = chefprojetBot.search(new JSONObject()
						.put("nom", values[6].split(",[]*")[0])
						.put("prenom",values[6].split(",[]*")[1])
						);
					
						if (rs.size() == 1) // 1 found = update
						chefprojetBo.setValues(rs.get(0), true);	
						
						else if (rs.size() == 0) // 0 found => create
						chefprojetBo.resetValues(true); // 
					
						else // Should never happen if search is done using all functional keys
						throw new Exception(rs.size() + " records found");
						
						chefprojetBo.setFieldValue("nom", values[6].split(",[]*")[0]);
						chefprojetBo.setFieldValue("prenom", values[6].split(",[]*")[1]);	  
						chefprojetBot.validateAndSave();
						}
					else // Should never happen if search is done using all functional keys
						throw new Exception(rs.size() + " project chief records found");
			
				
					//Create/Update "Projet"
					projetBo.setFieldValue("numero_projet", values[3]);
					projetBo.setFieldValue("orgaProjet", values[2] );	  
					projetBo.setFieldValue("nomProjet", values[4] );
					projetBo.setFieldValue("nomTacheSup", values[5]);
					projetBo.setFieldValue("Projet_Contrat_id", contratBo.getFieldValue("row_id"));
					projetBo.setFieldValue("Projet_ChefProjet_id",chefprojetBo.getFieldValue("row_id") );
					projetBo.setFieldValue("numLigneContrat", values[1] );	  
				
					projetBot.validateAndSave();
					
				
	    			//Create/Update "Facture"
					List<String[]> rs_fac = factureBot.search(new JSONObject()
					.put("numEvt", values[10]));
					
					if (rs_fac.size() == 1) // 1 found = update
					factureBo.setValues(rs_fac.get(0), true);	
						
					else if (rs_fac.size() == 0) // 0 found => create
					factureBo.resetValues(true); // 
					
					else // Should never happen if search is done using all functional keys
					throw new Exception(rs_fac.size() + " invoice records found");
					
			
					
					//Date mapping from DD/MM/YYYY to YYYY/MM/DD
					 
					String dbDate = values[9].split("/")[2] +"-"+ values[9].split("/")[1]+ "-"+ values[9].split("/")[0];
				
					factureBo.setFieldValue("dateFinEvenement", dbDate );
					factureBo.setFieldValue("description", values[11] );
					
					//replace the comma by dot anb delete space from "montantNonFacture"
						
					String montantNonFacture = values[12].replaceAll(",",".");
				  
				
					factureBo.setFieldValue("montantNonFacture", montantNonFacture.replaceAll("\\s+","") );
					
					factureBo.setFieldValue("Facture_Projet_id", projetBo.getFieldValue("row_id") );
				
					
					factureBo.setFieldValue("reportFacturation", values[14] );
					factureBo.setFieldValue("commentaireFacture", values[15] );
					
					//replace the comma by dot anb delete space from "montantAFacturer"
					String montantAFacturer = values[16].replaceAll(",",".");
					   
					
					
					factureBo.setFieldValue("montantAFacturer", montantAFacturer.replaceAll("\\s+","") );
					factureBo.setFieldValue("statutEvtFacture", "REP" );
					
					//Status related to "type contrat" on the first import
					if (rs_fac.size() == 0 && (values[7].equals("Date à date") || values[7].equals("Epuisements de jours")) )
					factureBo.setFieldValue("statutEvtFacture", "FAC" );
					else 
					factureBo.setFieldValue("statutEvtFacture", "AFAC" );
				
					//Status related to "description" on evry import
					if (values[11].equals("pas de base factu") || values[11].equals("reste à facturer"))
					factureBo.setFieldValue("statutEvtFacture", "ATT" );
				
				
					factureBo.setFieldValue("TypeEvent", values[8] );
					factureBo.setFieldValue("numEvt", values[10]);
					
					
					factureBot.validateAndSave();
				
					
						
					
				
					}catch (Exception e) {
					
					}
		    	}
	    	}
	    	}
		}
					
				
			
						
				
	    		
	    	
	    	
	
	}
	

}

```

Merci d’avance,

---

<div class="post-metadata">

**Author:** ![scampano](https://community.simplicite.io/user_avatar/community.simplicite.io/scampano/32/10010_2.png) [@scampano](https://community.simplicite.io/u/scampano)\
**Post date:** [January 7, 2021, 11:23am UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/8 "2021-01-07T11:23:05Z")

</div>

> [@Sofiane94](#):
>
> ```java
> catch (Exception e) {
> 					
> }
> 
> ```

Bonjour, vous ne pouvez pas ne pas traîter les exceptions comme vous l’avez fait! S’il y en a eu une, c’est normal que rien ne soit loggé vu ce que vous avez écrit…

Utilisez plutôt ceci:

```java
catch (Exception e) {
	AppLog.error(InvEvtCSVAdapter.class, "InvEvtCSVAdapter", e.getMessage(), e, Grant.getSystemAdmin());
	throw new InvEvtCSVAdapterException("INT_ADP_ERR_PROCESSING_LINE: "+e.getMessage());
}

```

_PS: Par ailleurs, je recommande vivement l’utilisation d’un analyseur de code de type [Sonar](https://www.sonarqube.org/) qui remonte automatiquement ce genre de mauvaises pratiques de développement Java, en cas de faute d’inattention. Votre fonction `processWithExceptions` mériterait aussi d’être décomposée par souci de lisibilité 😉_

---

<div class="post-metadata">

**Author:** ![system](https://community.simplicite.io/user_avatar/community.simplicite.io/system/32/4700_2.png) [@system](https://community.simplicite.io/u/system)\
**Post date:** [March 30, 2021, 6:46pm UTC](https://community.simplicite.io/t/import-csv-adapter-specifique/2843/9 "2021-03-30T18:46:50Z")

</div>

Closed on March 30, 2021, 6:46pm UTC


