diff --git a/met4j-chemUtils/src/main/java/fr/inrae/toulouse/metexplore/met4j_chemUtils/FormulaParser.java b/met4j-chemUtils/src/main/java/fr/inrae/toulouse/metexplore/met4j_chemUtils/FormulaParser.java
index 0cdf9b5a630debdbbedc9e27cb2e071e942f04b7..d3147808dcfb91a05cee2be930647d85d6149981 100644
--- a/met4j-chemUtils/src/main/java/fr/inrae/toulouse/metexplore/met4j_chemUtils/FormulaParser.java
+++ b/met4j-chemUtils/src/main/java/fr/inrae/toulouse/metexplore/met4j_chemUtils/FormulaParser.java
@@ -15,12 +15,10 @@ public class FormulaParser {
     String formula;
     Pattern inorgaRegex;
     Pattern groupMatch;
-    Pattern genericFormula = Pattern.compile("^([\\*\\(\\)A-Z][a-z]*\\d*)+$");;
     List<String> atoms = Arrays.asList("H","B","C","N","O","F","Na","Mg","Al","Si","P","S","Cl","K","Ca","Cr","Mn","Fe","Co","Cu","Zn","Se","Mo","Cd","Sn","I");
 
-
     public FormulaParser(String formula){
-        if(StringUtils.isVoid(formula) || !genericFormula.matcher(formula).find()) throw new IllegalArgumentException("Unable to parse formula");
+        if(StringUtils.isVoid(formula) || ! StringUtils.checkMetaboliteFormula(formula)) throw new IllegalArgumentException("Unable to parse formula");
         this.formula=formula;
     }
 
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEntity.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEntity.java
index 273c5a19c47524c761e1ff4ad9ed1ba7df38bea2..e180759448f53dfb9272909f2f0cf8c0ac10caad 100755
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEntity.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEntity.java
@@ -47,7 +47,7 @@ import fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils;
  */
 public abstract class BioEntity {
 
-    private final String id;
+    final String id;
     private String name;
     private ArrayList<String> synonyms = new ArrayList<>();
     private String comment;
@@ -103,26 +103,6 @@ public abstract class BioEntity {
         this.setAttributes(new HashMap<>(e.getAttributes()));
     }
 
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) return true;
-        if (o == null || getClass() != o.getClass()) return false;
-        BioEntity bioEntity = (BioEntity) o;
-        return id.equals(bioEntity.id);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(id);
-    }
-
     /**
      * Set the name of the entity
      *
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipant.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipant.java
index 775d1be3498ae65c463ee76864ea4c419197d7db..b8e3836c41846c57440dcd6433d6702df37060ce 100644
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipant.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipant.java
@@ -54,8 +54,8 @@ public class BioEnzymeParticipant extends BioParticipant {
      * @param physicalEntity the physical entity that is contained in the enzyme
      * @param stoichiometry  the number of unities of the physical entity
      */
-    public BioEnzymeParticipant(BioPhysicalEntity physicalEntity, Double stoichiometry) {
-        super(physicalEntity, stoichiometry);
+    protected BioEnzymeParticipant(BioPhysicalEntity physicalEntity, Double stoichiometry) {
+        super(physicalEntity.getId() + "__" + stoichiometry, physicalEntity, stoichiometry);
     }
 
     /**
@@ -65,7 +65,7 @@ public class BioEnzymeParticipant extends BioParticipant {
      *                       The stoichiometry is put to 1.
      */
     public BioEnzymeParticipant(BioPhysicalEntity physicalEntity) {
-        super(physicalEntity, 1.0);
+        this(physicalEntity, 1.0);
     }
 
     /**
@@ -92,7 +92,7 @@ public class BioEnzymeParticipant extends BioParticipant {
 
         }
 
-        String buffer = quantityStr + " " + this.getId();
+        String buffer = quantityStr + " " + this.getPhysicalEntity().getId();
 
         return buffer;
 
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetwork.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetwork.java
index 21761807927e69729370124184fd09eca0a58e72..03683bf579d1686ac2c41651c2f86a03a8ea594f 100755
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetwork.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetwork.java
@@ -41,10 +41,7 @@ package fr.inrae.toulouse.metexplore.met4j_core.biodata;
 
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection;
 
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -72,6 +69,10 @@ public class BioNetwork extends BioEntity {
 
     private final BioCollection<BioEnzyme> enzymes = new BioCollection<>();
 
+    private final BioCollection<BioReactant> reactants = new BioCollection<>();
+
+    private final BioCollection<BioEnzymeParticipant> enzymeParticipants = new BioCollection<>();
+
     /**
      * <p>Constructor for BioNetwork.</p>
      *
@@ -533,7 +534,7 @@ public class BioNetwork extends BioEntity {
      * @param reaction  a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction}
      * @param reactants a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection} {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant}
      */
-    public void affectLeft(BioReaction reaction, BioCollection<BioReactant> reactants) {
+    protected void affectLeft(BioReaction reaction, BioCollection<BioReactant> reactants) {
         this.affectLeft(reaction, reactants.toArray(new BioReactant[0]));
     }
 
@@ -613,7 +614,7 @@ public class BioNetwork extends BioEntity {
      * @param reaction  a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction}
      * @param reactants a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection} {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant} of {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant}
      */
-    public void affectRight(BioReaction reaction, BioCollection<BioReactant> reactants) {
+    protected void affectRight(BioReaction reaction, BioCollection<BioReactant> reactants) {
         this.affectRight(reaction, reactants.toArray(new BioReactant[0]));
     }
 
@@ -629,8 +630,27 @@ public class BioNetwork extends BioEntity {
         removeSideReaction(e, localisation, reaction, BioReaction.Side.RIGHT);
     }
 
+    /**
+     * get a reactant with the same metabolite, stoichiometry and compartment
+     *
+     * @param metabolite
+     * @param stoichiometry
+     * @param compartment
+     * @return
+     */
+    protected BioReactant getReactant(BioMetabolite metabolite, Double stoichiometry, BioCompartment compartment) {
+        Optional<BioReactant> any = this.reactants.stream()
+                .filter(r -> r.getMetabolite().equals(metabolite) &&
+                        r.getQuantity().equals(stoichiometry)
+                        && r.getLocation().equals(compartment)).findAny();
+        if (any.isPresent()) {
+            return any.get();
+        }
+        return null;
+    }
+
     private void affectSideReaction(BioReaction reaction, Double stoichiometry, BioCompartment localisation, BioReaction.Side side, BioMetabolite e) {
-        BioReactant reactant = new BioReactant(e, stoichiometry, localisation);
+
 
         // The network must contain the compartment
         if (!this.compartments.contains(localisation)) {
@@ -651,6 +671,13 @@ public class BioNetwork extends BioEntity {
             throw new IllegalArgumentException("Reaction " + reaction.getId() + " not in the network");
         }
 
+        BioReactant reactant = this.getReactant(e, stoichiometry, localisation);
+
+        if (reactant == null) {
+            reactant = new BioReactant(e, stoichiometry, localisation);
+            this.reactants.add(reactant);
+        }
+
         if (side.equals(BioReaction.Side.LEFT)) {
             reaction.getLeftReactants().add(reactant);
         } else {
@@ -658,11 +685,29 @@ public class BioNetwork extends BioEntity {
         }
     }
 
+    private void addReactant(BioReactant reactant) {
+        this.reactants.add(reactant);
+    }
+
+    /**
+     * Add reactants in the list of reactants
+     * @param reactants
+     */
+    protected void addReactants(BioReactant ...reactants) {
+        for(BioReactant r : reactants) {
+            this.addReactant(r);
+        }
+    }
+
 
     private void affectSideReaction(BioReactant reactant, BioReaction reaction, BioReaction.Side side) {
 
         BioCompartment localisation = reactant.getLocation();
 
+        if (! this.reactants.contains(reactant)) {
+            throw new IllegalArgumentException("Reactant " + reactant.getId() + " not in the network");
+        }
+
         // The network must contain the compartment
         if (!this.compartments.contains(localisation)) {
             throw new IllegalArgumentException("Compartment " + localisation.getId() + " not in the network");
@@ -685,9 +730,13 @@ public class BioNetwork extends BioEntity {
         }
 
         if (side.equals(BioReaction.Side.LEFT)) {
-            reaction.getLeftReactants().add(reactant);
+            if (!reaction.getLeftReactants().containsId(reactant.getId())) {
+                reaction.getLeftReactants().add(reactant);
+            }
         } else {
-            reaction.getRightReactants().add(reactant);
+            if (!reaction.getRightReactants().containsId(reactant.getId())) {
+                reaction.getRightReactants().add(reactant);
+            }
         }
     }
 
@@ -786,6 +835,23 @@ public class BioNetwork extends BioEntity {
 
     }
 
+    /**
+     * Get enzyme participant with the same quantity and the same entity
+     *
+     * @param quantity
+     * @param unit
+     * @return
+     */
+    protected BioEnzymeParticipant getEnzymeParticipant(BioPhysicalEntity unit, Double quantity) {
+        Optional<BioEnzymeParticipant> any = this.enzymeParticipants.stream()
+                .filter(e -> e.getPhysicalEntity().equals(unit) && e.getQuantity().equals(quantity))
+                .findAny();
+
+        if (any.isPresent()) {
+            return any.get();
+        } else return null;
+    }
+
     /**
      * Add a subunit to an enzymes
      *
@@ -796,8 +862,6 @@ public class BioNetwork extends BioEntity {
      */
     private void affectSubUnit(BioEnzyme enzyme, Double quantity, BioPhysicalEntity unit) {
 
-        BioEnzymeParticipant p = new BioEnzymeParticipant(unit, quantity);
-
         if (!this.contains(enzyme)) {
             throw new IllegalArgumentException("Enzyme " + enzyme.getId() + " not present in the network");
         }
@@ -806,6 +870,12 @@ public class BioNetwork extends BioEntity {
             throw new IllegalArgumentException("Physical entity " + unit.getId() + " not present in the network");
         }
 
+        BioEnzymeParticipant p = this.getEnzymeParticipant(unit, quantity);
+        if (p == null) {
+            p = new BioEnzymeParticipant(unit, quantity);
+            this.enzymeParticipants.add(p);
+        }
+
         enzyme.addParticipant(p);
 
     }
@@ -819,6 +889,9 @@ public class BioNetwork extends BioEntity {
      */
     private void affectSubUnit(BioEnzyme enzyme, BioEnzymeParticipant unit) {
 
+        if(! this.enzymeParticipants.contains(unit)) {
+            throw new IllegalArgumentException("Enzyme participant " + unit.getId() + " not present in the network");
+        }
 
         if (!this.contains(enzyme)) {
             throw new IllegalArgumentException("Enzyme " + enzyme.getId() + " not present in the network");
@@ -828,7 +901,9 @@ public class BioNetwork extends BioEntity {
             throw new IllegalArgumentException("Physical entity " + unit.getPhysicalEntity().getId() + " not present in the network");
         }
 
-        enzyme.addParticipant(unit);
+        if(! enzyme.getParticipants().containsId(unit.getId())) {
+            enzyme.addParticipant(unit);
+        }
 
     }
 
@@ -882,7 +957,7 @@ public class BioNetwork extends BioEntity {
      * @param enzyme a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEnzyme}
      * @param units  a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection} of {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEnzymeParticipant}
      */
-    public void affectSubUnit(BioEnzyme enzyme, BioCollection<BioEnzymeParticipant> units) {
+    protected void affectSubUnit(BioEnzyme enzyme, BioCollection<BioEnzymeParticipant> units) {
 
         for (BioEnzymeParticipant unit : units) {
             affectSubUnit(enzyme, unit);
@@ -1178,7 +1253,7 @@ public class BioNetwork extends BioEntity {
     }
 
     /**
-     * @param m a {@link BioMetabolite}
+     * @param m           a {@link BioMetabolite}
      * @param isSubstrate a {@link Boolean} indicating if the metabolite is a substrate or a product
      * @return a {@link BioCollection} of {@link BioReaction}
      */
@@ -1776,4 +1851,56 @@ public class BioNetwork extends BioEntity {
     public int hashCode() {
         return Objects.hash(super.hashCode(), pathways, metabolites, proteins, genes, reactions, compartments, enzymes);
     }
+
+
+    /**
+     * @param e
+     * @return
+     */
+    public Boolean containsEntityWithSameId(BioEntity e) {
+        if (e == null) {
+            throw new NullPointerException();
+        }
+
+        String id = e.getId();
+
+        Boolean flag;
+
+        if (e instanceof BioPathway) {
+            flag = this.pathways.containsId(id);
+        } else if (e instanceof BioMetabolite) {
+            flag = this.metabolites.containsId(id);
+        } else if (e instanceof BioProtein) {
+            flag = this.proteins.containsId(id);
+        } else if (e instanceof BioGene) {
+            flag = this.genes.containsId(id);
+        } else if (e instanceof BioReaction) {
+            flag = this.reactions.containsId(id);
+        } else if (e instanceof BioCompartment) {
+            flag = this.compartments.containsId(id);
+        } else if (e instanceof BioEnzyme) {
+            flag = this.enzymes.containsId(id);
+        } else {
+
+            throw new IllegalArgumentException(
+                    "BioEntity \"" + e.getClass().getSimpleName() + "\" not supported by BioNetwork");
+        }
+        return flag;
+
+    }
+
+    /**
+     * Adds enzymes participants in the network
+     * @param enzymeParticipants
+     */
+    protected void addEnzymeParticipants(BioEnzymeParticipant ...enzymeParticipants) {
+        for(BioEnzymeParticipant ep : enzymeParticipants) {
+            this.addEnzymeParticipant(ep);
+        }
+
+    }
+
+    private void addEnzymeParticipant(BioEnzymeParticipant ep) {
+        this.enzymeParticipants.add(ep);
+    }
 }
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipant.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipant.java
index db972165a0f1214b4b86dd75ce8d39647d8cd617..d51b10db5b89bc5dd4effa824e3e5c77ba2d818c 100755
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipant.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipant.java
@@ -38,6 +38,7 @@ package fr.inrae.toulouse.metexplore.met4j_core.biodata;
 
 import fr.inrae.toulouse.metexplore.met4j_core.utils.ErrorUtils;
 
+import javax.annotation.Nonnull;
 import java.util.Objects;
 
 /**
@@ -48,9 +49,9 @@ import java.util.Objects;
  */
 public abstract class BioParticipant extends BioEntity {
 
-	private BioPhysicalEntity physicalEntity;
+	private final BioPhysicalEntity physicalEntity;
 	
-	private Double quantity;
+	private final Double quantity;
 
 	/**
 	 * Constructor
@@ -58,13 +59,20 @@ public abstract class BioParticipant extends BioEntity {
 	 * @param physicalEntity a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioPhysicalEntity}
 	 * @param quantity number of units of physicalEntity
 	 */
-	public BioParticipant(BioPhysicalEntity physicalEntity, Double quantity) {
-		super(physicalEntity.getId());
+
+	public BioParticipant(String id, @Nonnull BioPhysicalEntity physicalEntity, Double quantity) {
+		super(id);
 		this.physicalEntity=physicalEntity;
-		this.setQuantity(quantity);
+		if(Double.isNaN(quantity) || Double.isInfinite(quantity) || quantity <= 0)
+		{
+			ErrorUtils.error("Illegal argument for "+quantity+" "+this.getPhysicalEntity().getId()+": the quantity must be finite and positive");
+			throw new IllegalArgumentException();
+		}
+
+		this.quantity = quantity;
 	}
-	
-	
+
+
 	/**
 	 * <p>Getter for the field <code>physicalEntity</code>.</p>
 	 *
@@ -75,18 +83,6 @@ public abstract class BioParticipant extends BioEntity {
 	}
 	
 
-	/**
-	 * <p>Setter for the field <code>physicalEntity</code>.</p>
-	 *
-	 * @param physicalEntity the physicalEntity to set
-	 */
-	public void setPhysicalEntity(BioPhysicalEntity physicalEntity) {
-		this.physicalEntity = physicalEntity;
-	}
-	
-	
-
-
 	/**
 	 * <p>Getter for the field <code>quantity</code>.</p>
 	 *
@@ -97,28 +93,11 @@ public abstract class BioParticipant extends BioEntity {
 	}
 
 
-	/**
-	 * <p>Setter for the field <code>quantity</code>.</p>
-	 *
-	 * @param quantity the quantity to set
-	 */
-	public void setQuantity(Double quantity) {
-		
-		if(Double.isNaN(quantity) || Double.isInfinite(quantity) || quantity <= 0)
-		{
-			ErrorUtils.error("Illegal argument for "+quantity+" "+this.getPhysicalEntity().getId()+": the quantity must be finite and positive");
-			throw new IllegalArgumentException();
-		}
-		
-		this.quantity = quantity;
-	}
-
 	/** {@inheritDoc} */
 	@Override
 	public boolean equals(Object o) {
 		if (this == o) return true;
 		if (o == null || getClass() != o.getClass()) return false;
-		if (!super.equals(o)) return false;
 		BioParticipant that = (BioParticipant) o;
 		return Objects.equals(physicalEntity, that.physicalEntity) &&
 				Objects.equals(quantity, that.quantity);
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactant.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactant.java
index 876ae1564765257da6bc46f76f1b42be2f6b9436..fcb3b7ab9ff7f0b79fdc82bad59379662f820e41 100644
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactant.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactant.java
@@ -35,6 +35,7 @@
  */
 package fr.inrae.toulouse.metexplore.met4j_core.biodata;
 
+import javax.annotation.Nonnull;
 import java.text.DecimalFormat;
 import java.text.DecimalFormatSymbols;
 import java.text.NumberFormat;
@@ -49,7 +50,7 @@ import java.util.Objects;
  */
 public class BioReactant extends BioParticipant {
 
-	private BioCompartment location = null;
+	private final BioCompartment location;
 
 	/**
 	 * Constructor
@@ -58,9 +59,9 @@ public class BioReactant extends BioParticipant {
 	 * @param stoichiometry stoichiometric coefficient
 	 * @param location a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment}
 	 */
-	public BioReactant(BioMetabolite metabolite, Double stoichiometry, BioCompartment location) {
-		super(metabolite, stoichiometry);
-		this.setLocation(location);
+	protected BioReactant(@Nonnull BioMetabolite metabolite, Double stoichiometry, @Nonnull BioCompartment location) {
+		super(metabolite.getId()+"__"+stoichiometry+"__"+location.getId(), metabolite, stoichiometry);
+		this.location = location;
 	}
 
 	/**
@@ -72,15 +73,6 @@ public class BioReactant extends BioParticipant {
 		return location;
 	}
 
-	/**
-	 * Set location
-	 *
-	 * @param location a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment}
-	 */
-	protected void setLocation(BioCompartment location) {
-		this.location = location;
-	}
-
 	/**
 	 * Get the associated metabolite
 	 *
@@ -114,7 +106,7 @@ public class BioReactant extends BioParticipant {
 
 		StringBuilder buffer = new StringBuilder(quantityStr);
 		buffer.append(" ");
-		buffer.append(this.getId());
+		buffer.append(this.getPhysicalEntity().getId());
 		if (this.getLocation() != null) {
 			buffer.append("[");
 			buffer.append(this.getLocation().getId());
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollection.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollection.java
index 9bd3b4991970582f5f7572378dfd61ccbe2f2e0c..6d78f8f54deeda7b83f88819970570d0e0cbb7e2 100644
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollection.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollection.java
@@ -198,7 +198,15 @@ public class BioCollection<E extends BioEntity> implements Collection<E> {
 	/** {@inheritDoc} */
 	@Override
 	public boolean add(E e) {
-		entities.put(e.getId(), e);
+		if(entities.containsValue(e)) {
+			return false;
+		}
+		else {
+			if (entities.keySet().contains(e.getId())) {
+				throw new IllegalArgumentException("An entity with the same id (" + e.getId() + ") is already present in the BioCollection");
+			}
+			entities.put(e.getId(), e);
+		}
 		return true;
 	}
 
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtils.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtils.java
index 39d85f44e2eea83ca6b75b7b9a4e0b9f89fb21fa..123c92b33ffa5316100ca28e5c282b3ce2540489 100644
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtils.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtils.java
@@ -136,12 +136,14 @@ public class BioNetworkUtils {
         }
 
         for (BioMetabolite metabolite : metabolitesToCopy) {
-            BioMetabolite newMetabolite = new BioMetabolite(metabolite);
-            networkOut.add(newMetabolite);
+            BioMetabolite newMetabolite;
+            if (!networkOut.containsEntityWithSameId(metabolite)) {
+                newMetabolite = new BioMetabolite(metabolite);
+                networkOut.add(newMetabolite);
+            }
         }
 
-        // Copy compartments (empty for the moment)
-        // Copy metabolites
+        // Copy compartments
         BioCollection<BioCompartment> compartmentsToCopy = networkIn.getCompartmentsView();
         if (keepPrevious) {
             compartmentsToCopy.removeAll(networkOut.getCompartmentsView());
@@ -151,7 +153,7 @@ public class BioNetworkUtils {
 
             BioCompartment newCpt;
 
-            if (compartmentsToCopy.contains(cpt)) {
+            if (compartmentsToCopy.contains(cpt) && (!networkOut.containsEntityWithSameId(cpt))) {
                 newCpt = new BioCompartment(cpt);
                 networkOut.add(newCpt);
             } else {
@@ -176,8 +178,10 @@ public class BioNetworkUtils {
             }
 
             for (BioGene gene : genesToCopy) {
-                BioGene newGene = new BioGene(gene);
-                networkOut.add(newGene);
+                if (!networkOut.containsEntityWithSameId(gene)) {
+                    BioGene newGene = new BioGene(gene);
+                    networkOut.add(newGene);
+                }
             }
         }
 
@@ -191,7 +195,7 @@ public class BioNetworkUtils {
 
                 BioProtein newProtein;
 
-                if (proteinsToCopy.contains(protein)) {
+                if (proteinsToCopy.contains(protein) && (!networkOut.containsEntityWithSameId(protein))) {
                     newProtein = new BioProtein(protein);
                     networkOut.add(newProtein);
                 } else {
@@ -218,7 +222,7 @@ public class BioNetworkUtils {
 
                 BioEnzyme newEnzyme;
 
-                if (enzymesToCopy.contains(enzyme)) {
+                if (enzymesToCopy.contains(enzyme) && !networkOut.containsEntityWithSameId(enzyme)) {
                     newEnzyme = new BioEnzyme(enzyme);
                     networkOut.add(newEnzyme);
                 } else {
@@ -230,25 +234,19 @@ public class BioNetworkUtils {
                 for (BioEnzymeParticipant participant : participants) {
                     Double quantity = participant.getQuantity();
 
-                    BioEnzymeParticipant newParticipant = null;
                     if (participant.getPhysicalEntity().getClass().equals(BioMetabolite.class)) {
                         BioMetabolite metabolite = (BioMetabolite) participant.getPhysicalEntity();
                         BioMetabolite newMetabolite = networkOut.getMetabolitesView().get(metabolite.getId());
-                        newParticipant = new BioEnzymeParticipant(newMetabolite, quantity);
+                        networkOut.affectSubUnit(newEnzyme, quantity, newMetabolite);
                     } else if (participant.getPhysicalEntity().getClass().equals(BioProtein.class)) {
                         BioProtein protein = (BioProtein) participant.getPhysicalEntity();
                         BioProtein newProtein = networkOut.getProteinsView().get(protein.getId());
-                        newParticipant = new BioEnzymeParticipant(newProtein, quantity);
+                        networkOut.affectSubUnit(newEnzyme, quantity, newProtein);
                     } else {
                         System.err.println("BioPhysical entity not recognized as enzyme participant : "
                                 + participant.getPhysicalEntity().getId()
                                 + "(" + participant.getPhysicalEntity().getClass() + ")");
                     }
-
-                    if (newParticipant != null) {
-                        networkOut.affectSubUnit(newEnzyme, newParticipant);
-                    }
-
                 }
             }
         }
@@ -264,7 +262,7 @@ public class BioNetworkUtils {
 
             BioReaction newReaction;
 
-            if (reactionsToCopy.contains(r)) {
+            if (reactionsToCopy.contains(r) && !networkOut.containsEntityWithSameId(r)) {
 
                 newReaction = new BioReaction(r);
                 newReaction.setSpontaneous(r.isSpontaneous());
@@ -281,9 +279,7 @@ public class BioNetworkUtils {
                 BioMetabolite newMetabolite = networkOut.getMetabolitesView().get(reactant.getMetabolite().getId());
                 BioCompartment newCpt = networkOut.getCompartmentsView().get(reactant.getLocation().getId());
                 Double sto = reactant.getQuantity();
-                BioReactant newReactant = new BioReactant(newMetabolite, sto, newCpt);
-
-                networkOut.affectLeft(newReaction, newReactant);
+                networkOut.affectLeft(newReaction, sto, newCpt, newMetabolite);
             }
 
             // Copy rights
@@ -291,9 +287,7 @@ public class BioNetworkUtils {
                 BioMetabolite newMetabolite = networkOut.getMetabolitesView().get(reactant.getMetabolite().getId());
                 BioCompartment newCpt = networkOut.getCompartmentsView().get(reactant.getLocation().getId());
                 Double sto = reactant.getQuantity();
-                BioReactant newReactant = new BioReactant(newMetabolite, sto, newCpt);
-
-                networkOut.affectRight(newReaction, newReactant);
+                networkOut.affectRight(newReaction, sto, newCpt, newMetabolite);
             }
 
             // Copy enzymes
@@ -313,7 +307,7 @@ public class BioNetworkUtils {
 
         for (BioPathway pathway : networkIn.getPathwaysView()) {
 
-            if (pathwaysToCopy.contains(pathway)) {
+            if (pathwaysToCopy.contains(pathway) && !networkOut.containsEntityWithSameId(pathway)) {
                 BioPathway newPathway = new BioPathway(pathway);
                 networkOut.add(newPathway);
             }
diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java
index b96e5f5e75fa70bff25d8bf081f8d6e88074ce16..916fb7fcc1f0c093748b2cd05738aa2d895ff1fb 100644
--- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java
+++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java
@@ -36,6 +36,9 @@
 
 package fr.inrae.toulouse.metexplore.met4j_core.utils;
 
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
 /**
  * <p>StringUtils class.</p>
  *
@@ -44,6 +47,9 @@ package fr.inrae.toulouse.metexplore.met4j_core.utils;
  */
 public class StringUtils {
 
+	private static Pattern patternEC = Pattern.compile("(EC\\s*)*\\d{1}(\\.(\\d{0,3}|-)){0,3}");
+	private static Pattern patternFormula = Pattern.compile("^([\\*\\(\\)A-Z][a-z]*\\d*)+$");;
+
 	/**
 	 * <p>isVoid.</p>
 	 *
@@ -90,4 +96,24 @@ public class StringUtils {
 		return true;
 	}
 
+	/**
+	 * Check EC number
+	 * @param ec
+	 * @return
+	 */
+	public static  boolean checkEcNumber(String ec) {
+		Matcher m = patternEC.matcher(ec);
+		return m.matches();
+	}
+
+	/**
+	 * Checks if a metabolite formula is well formatted
+	 * @param formula
+	 * @return
+	 */
+	public static boolean checkMetaboliteFormula(String formula) {
+		Matcher m = patternFormula.matcher(formula);
+		return m.matches();
+	}
+
 }
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipantTest.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipantTest.java
index 8ad561b5e5b5b81fa4bcd7dcc2e21146a5624286..0afd0b42f07a087b6fc0f8e445fbe0badd82334e 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipantTest.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioEnzymeParticipantTest.java
@@ -44,33 +44,16 @@ import org.junit.Test;
 
 
 public class BioEnzymeParticipantTest {
-	
+
 
 	@Test
 	public void testToString() {
-		
+
 		BioEnzymeParticipant p = new BioEnzymeParticipant(new BioProtein("p1"), 2.0);
-		
+
 		assertEquals("toString does not work", "2 p1", p.toString());
-		
-		
-	}
 
 
-	@Test
-	public void testEquality() {
-		
-		
-		BioEnzymeParticipant p = new BioEnzymeParticipant(new BioProtein("p1"), 2.0);
-		BioEnzymeParticipant p2 = new BioEnzymeParticipant(new BioProtein("p2"), 2.0);
-		BioEnzymeParticipant pBis = new BioEnzymeParticipant(new BioProtein("p1"), 2.0);
-		
-		assertNotEquals("p and p2 must not be equal", p, p2);
-		
-		assertEquals("p and pBis must be equal", p, pBis);
-		
-		
 	}
-
-
 }
+
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetworkTest.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetworkTest.java
index d5741d5ad6b29f6559d0b5ea40f1168b38165185..03379ecfc852fea8f0f0e8f90b972919bb42f64b 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetworkTest.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioNetworkTest.java
@@ -467,14 +467,13 @@ public class BioNetworkTest {
 
         network.affectLeft(reaction, 1.0, cpt, s1);
 
-        BioReactant reactant = new BioReactant(s2, 1.0, cpt);
-        network.affectLeft(reaction, reactant);
+        network.affectLeft(reaction, 1.0, cpt, s2);
 
         assertEquals("Substrate not well added", 2, reaction.getLeftReactants().size());
 
     }
 
-    @Test (expected = IllegalArgumentException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testAffectSubstrateMetaboliteNotPresent() {
 
         BioReaction reaction = new BioReaction("r1");
@@ -493,7 +492,7 @@ public class BioNetworkTest {
      * the metabolite has been removed from the network
      * Must throw an exception
      */
-    @Test (expected = IllegalArgumentException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testAffectSubstrateMetaboliteNotPresent2() {
 
         BioReaction reaction = new BioReaction("r1");
@@ -522,7 +521,7 @@ public class BioNetworkTest {
     /**
      *
      */
-    @Test (expected = IllegalArgumentException.class)
+    @Test(expected = IllegalArgumentException.class)
     public void testAffectSubstrateMetaboliteNotInCompartment() {
 
         BioReaction reaction = new BioReaction("r1");
@@ -540,25 +539,15 @@ public class BioNetworkTest {
     @Test
     public void testAffectSubstrateCollection() {
 
-        BioReaction reaction = new BioReaction("r1");
-        network.add(reaction);
-        BioMetabolite s1 = new BioMetabolite("s1");
-        network.add(s1);
-        BioMetabolite s2 = new BioMetabolite("s2");
-        network.add(s2);
-        BioCompartment cpt = new BioCompartment("cpt");
-        network.add(cpt);
-
-        BioReactant reactant1 = new BioReactant(s1, 1.0, cpt);
-        BioReactant reactant2 = new BioReactant(s2, 1.0, cpt);
-        BioCollection<BioReactant> reactants = new BioCollection<>();
-        reactants.add(reactant1, reactant2);
+        BioReaction reaction1 = this.addTestReactionToNetwork();
+        BioCollection<BioReactant> reactants = reaction1.getLeftReactants();
 
-        network.affectToCompartment(cpt, s1, s2);
+        BioReaction reaction2 = new BioReaction("r2");
+        this.network.add(reaction2);
 
-        network.affectLeft(reaction, reactants);
+        network.affectLeft(reaction2, reactants);
 
-        assertEquals("Substrate collection not well added", 2, reaction.getLeftReactants().size());
+        assertEquals("Substrate collection not well added", 2, reaction2.getLeftReactants().size());
 
     }
 
@@ -587,25 +576,18 @@ public class BioNetworkTest {
     @Test
     public void testAffectProductsCollection() {
 
-        BioReaction reaction = new BioReaction("r1");
-        network.add(reaction);
-        BioMetabolite s1 = new BioMetabolite("s1");
-        network.add(s1);
-        BioMetabolite s2 = new BioMetabolite("s2");
-        network.add(s2);
-        BioCompartment cpt = new BioCompartment("cpt");
-        network.add(cpt);
+        BioReaction reaction1 = addTestReactionToNetwork();
+
+        BioReaction reaction2 = new BioReaction("r2");
+        network.add(reaction2);
 
-        BioReactant reactant1 = new BioReactant(s1, 1.0, cpt);
-        BioReactant reactant2 = new BioReactant(s2, 1.0, cpt);
-        BioCollection<BioReactant> reactants = new BioCollection<>();
-        reactants.add(reactant1, reactant2);
+        BioCollection<BioReactant> reactants = reaction1.getRightReactants();
 
         network.affectToCompartment(cpt, s1, s2);
 
-        network.affectRight(reaction, reactants);
+        network.affectRight(reaction2, reactants);
 
-        assertEquals("Product collection not well added", 2, reaction.getRightReactants().size());
+        assertEquals("Product collection not well added", 2, reaction2.getRightReactants().size());
 
     }
 
@@ -745,8 +727,7 @@ public class BioNetworkTest {
         network.affectToCompartment(cpt, s1, s2);
 
         network.affectRight(reaction, 1.0, cpt, s1);
-        BioReactant reactant = new BioReactant(s2, 1.0, cpt);
-        network.affectRight(reaction, reactant);
+        network.affectRight(reaction, 1.0, cpt, s2);
 
         assertEquals("Product not well added", 2, reaction.getRightReactants().size());
     }
@@ -1666,5 +1647,17 @@ public class BioNetworkTest {
 
     }
 
+    @Test
+    public void testGetEnzymeParticipant() {
 
+        BioProtein p1 = new BioProtein("p1");
+        BioEnzyme e1 = new BioEnzyme("e1");
+        BioEnzymeParticipant participant = new BioEnzymeParticipant(p1, 2.0);
+
+        network.add(p1, e1);
+        network.affectSubUnit(e1, 2.0, p1);
+
+        assertNotNull(network.getEnzymeParticipant(p1, 2.0));
+        assertEquals(participant, network.getEnzymeParticipant(p1, 2.0));
+    }
 }
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipantTest.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipantTest.java
index 8c7d7d9e46b0bdcc09e22458d0d6cba15d2ee341..42f9f7d57984f61bb66506d282bc73f58a331094 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipantTest.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioParticipantTest.java
@@ -48,9 +48,7 @@ public class BioParticipantTest {
 	@Test(expected = IllegalArgumentException.class)
 	public void testSetNaNQuantity() {
 
-		BioParticipant p = new BioParticipantFake(new BioMetabolite("test"), 2.0);
-		Double nan = Double.NaN;
-		p.setQuantity(nan);
+		BioParticipant p = new BioParticipantFake(new BioMetabolite("test"),  Double.NaN);
 
 	}
 	
@@ -60,9 +58,7 @@ public class BioParticipantTest {
 	@Test(expected = IllegalArgumentException.class)
 	public void testSetInfiniteQuantity() {
 
-		BioParticipant p = new BioParticipantFake(new BioMetabolite("test"), 2.0);
-		Double inf = Double.POSITIVE_INFINITY;
-		p.setQuantity(inf);
+		BioParticipant p = new BioParticipantFake(new BioMetabolite("test"), Double.POSITIVE_INFINITY);
 	}
 	
 	/**
@@ -71,12 +67,9 @@ public class BioParticipantTest {
 	@Test(expected = IllegalArgumentException.class)
 	public void testSetNegativeOrNullQuantity() {
 
-		BioParticipant p = new BioParticipantFake(new BioMetabolite("test"), 2.0);
-		Double n = 0.0;
-		p.setQuantity(n);
-		
-		n = -10.0;
-		p.setQuantity(n);
+		new BioParticipantFake(new BioMetabolite("test"), 0.0);
+
+		new BioParticipantFake(new BioMetabolite("test"), -10.0);
 	}
 
 }
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactantTest.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactantTest.java
index a69953bb0cad9e7a70db8ca9e817f83e4ec97c13..f7c8fa061464dffb0a890ae87a6f908f4299143e 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactantTest.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactantTest.java
@@ -55,33 +55,19 @@ public class BioReactantTest {
 		reactant = new BioReactant(new BioMetabolite("cpdId"), 1.26666, new BioCompartment("cptId"));
 		assertEquals("reactant badly formatted (integer coefficient)", "1.27 cpdId[cptId]", reactant.toString());
 		
-		// Test when the biocompartment is null
-		reactant = new BioReactant(new BioMetabolite("cpdId"), 1.0, null);
-		assertEquals("reactant badly formatted (integer coefficient)", "1 cpdId", reactant.toString());
-		
 	}
 
-
 	@Test
-	public void testEquality() {
-	
-		BioMetabolite c1 = new BioMetabolite("c1");
-		BioCompartment cpt1 = new BioCompartment("cpt1");
-		BioMetabolite c2 = new BioMetabolite("c2");
-		BioCompartment cpt2 = new BioCompartment("cpt2");
-		
-		BioReactant r1 = new BioReactant(c1, 1.0, cpt1);
-		BioReactant r2 = new BioReactant(c1, 2.0, cpt1);
-		BioReactant r3 = new BioReactant(c1, 1.0, cpt2);
-		BioReactant r4 = new BioReactant(c2, 1.0, cpt1);
-		BioReactant r5 = new BioReactant(c1, 1.0, cpt1);
-		
-		assertFalse("r1 and r2 must not  be equal", r1.equals(r2));
-		assertFalse("r1 and r3 must not be equal", r1.equals(r3));
-		assertFalse("r1 and r4 must not be equal", r1.equals(r4));
-		assertTrue("r1 and r5 must be equal", r1.equals(r5));
-		
-	}
+	public void testEquals() {
+
+		BioMetabolite m1 = new BioMetabolite("m1");
+		BioCompartment c1 = new BioCompartment("c1");
+
+		BioReactant reactant1 = new BioReactant(m1, 2.0, c1);
+		BioReactant reactant2 = new BioReactant(m1, 2.0, c1);
 
+		assertTrue(reactant1.equals(reactant2));
+
+	}
 
 }
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactionTest.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactionTest.java
index 5aaf1bcbf1fcdd873bfb164d40c300f172a0c2d2..6388b5c9bf099492b68895758f97e865992b97d2 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactionTest.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/BioReactionTest.java
@@ -56,7 +56,7 @@ public class BioReactionTest {
 	public static BioMetabolite l1, l2, r1, r2;
 	public static BioReactant l1Reactant, l2Reactant, r1Reactant, r2Reactant;
 
-	public static BioReaction reaction;
+	public static BioReaction reaction, reaction2;
 
 	public static BioGene g1, g2, g3;
 
@@ -79,15 +79,21 @@ public class BioReactionTest {
 		r2Reactant = new BioReactant(r2, 1.0, cpt2);
 
 		reaction = new BioReaction("testreaction");
+		reaction2 = new BioReaction("testreaction2");
 
-		network.add(reaction, cpt1, cpt2, l1, l2, r1, r2);
+		network.add(reaction, reaction2, cpt1, cpt2, l1, l2, r1, r2);
 
 		network.affectToCompartment(cpt1, l1, l2);
 		network.affectToCompartment(cpt2, r1, r2);
 
+		network.addReactants(l1Reactant, l2Reactant, r1Reactant, r2Reactant);
+
 		network.affectLeft(reaction, l1Reactant, l2Reactant);
 		network.affectRight(reaction, r1Reactant, r2Reactant);
 
+		network.affectLeft(reaction2, l1Reactant);
+		network.affectRight(reaction2, l2Reactant);
+
 		BioEnzyme e1 = new BioEnzyme("e1");
 		BioProtein p1 = new BioProtein("p1");
 		BioProtein p2 = new BioProtein("p2");
@@ -104,6 +110,9 @@ public class BioReactionTest {
 		BioEnzymeParticipant ep1 = new BioEnzymeParticipant(p1);
 		BioEnzymeParticipant ep2 = new BioEnzymeParticipant(p2);
 		BioEnzymeParticipant ep3 = new BioEnzymeParticipant(p3);
+
+		network.addEnzymeParticipants(ep1, ep2, ep3);
+
 		network.affectSubUnit(e1, ep1);
 		network.affectSubUnit(e2, ep2, ep3);
 
@@ -136,11 +145,8 @@ public class BioReactionTest {
 		// Positive test
 		assertTrue("Must be a transport reaction", reaction.isTransportReaction());
 
-		// Negative Test
-		r1Reactant.setLocation(cpt1);
-		r2Reactant.setLocation(cpt1);
 
-		assertFalse("Must not be a transport reaction", reaction.isTransportReaction());
+		assertFalse("Must not be a transport reaction", reaction2.isTransportReaction());
 	}
 
 	/**
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/classesForTests/BioParticipantFake.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/classesForTests/BioParticipantFake.java
index 5f2b24b9d85887ef86f2fe870b681b1c8d8c2faf..98050a87766ac5dd262d34ac3dd643d863e0fd93 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/classesForTests/BioParticipantFake.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/classesForTests/BioParticipantFake.java
@@ -47,7 +47,7 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioPhysicalEntity;
 public class BioParticipantFake extends BioParticipant {
 
 	public BioParticipantFake(BioPhysicalEntity physicalEntity, Double quantity) {
-		super(physicalEntity, quantity);
+		super(physicalEntity.getId()+"__"+quantity, physicalEntity, quantity);
 	}
 
 }
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollectionTest.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollectionTest.java
index 2b97dc7875a80240627813dc9e90ef9f4445e804..e21ae7f1ca62526903c323254984a17b6b9fd9d1 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollectionTest.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/collection/BioCollectionTest.java
@@ -237,22 +237,4 @@ public class BioCollectionTest {
 
 	}
 
-	@Test
-	public void testEqualsObject() {
-
-		BioCollection<BioMetabolite> c2 = new BioCollection<BioMetabolite>();
-
-		BioMetabolite m1Bis = new BioMetabolite("m1", "metabolite1");
-		BioMetabolite m2Bis = new BioMetabolite("m2", "metabolite2");
-
-		c2.add(m1Bis);
-
-		assertFalse(collec.equals(c2));
-
-		c2.add(m2Bis);
-
-		assertTrue(collec.equals(c2));
-
-	}
-
 }
diff --git a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtilsTest.java b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtilsTest.java
index ea00bea8be88ad050d958aa60517dc4a339b69f6..1a627b9ad1d6ab9f7dfe630c6a0355dd8e5e107a 100644
--- a/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtilsTest.java
+++ b/met4j-core/src/test/java/fr/inrae/toulouse/metexplore/met4j_core/biodata/utils/BioNetworkUtilsTest.java
@@ -264,7 +264,7 @@ public class BioNetworkUtilsTest {
         assertEquals(2, newNetwork.getPathwaysView().size());
         assertEquals(2, enzyme1.getParticipantsView().size());
         // The gene must be updated
-        assertEquals(gene1, protein1.getGene());
+        assertEquals(gene1.getId(), protein1.getGene().getId());
         assertEquals(2, r1.getLeftReactantsView().size());
         assertEquals(2, r1.getEnzymesView().size());
         assertEquals(3, newNetwork.getReactionsFromPathways(pathway1).size());
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/compartment/CompartmentAttributes.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/compartment/CompartmentAttributes.java
index 9536199ba399d800c655d4796497c973106c8e83..105df1ceccd69b22ab09c32d30a95f4a6ad6fcec 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/compartment/CompartmentAttributes.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/compartment/CompartmentAttributes.java
@@ -67,8 +67,8 @@ public class CompartmentAttributes extends GenericAttributes {
 	 */
 	public static void setOutsideCompartment(BioCompartment c, BioCompartment outside) {
 
-		if (c.equals(outside)) {
-			throw new IllegalArgumentException("The compartment and the outside compartment must be different");
+		if (c.getId().equals(outside.getId())) {
+			throw new IllegalArgumentException("The compartment and the outside compartment have a different id");
 		}
 
 		c.setAttribute(OUTSIDE_COMPARTMENT, outside);
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/network/NetworkAttributes.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/network/NetworkAttributes.java
index 659e65edc5df5c261bb6d96a4c7b69e60ee0499c..4d4fcd10cdeee9d538e75336ff1b9d53bd921d7b 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/network/NetworkAttributes.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/network/NetworkAttributes.java
@@ -116,7 +116,13 @@ public class NetworkAttributes extends GenericAttributes {
 			addUnitDefinitions(network, new BioUnitDefinitionCollection());
 		}
 
-		getUnitDefinitions(network).add(unit);
+		BioUnitDefinitionCollection unitDefinitions = getUnitDefinitions(network);
+
+		if(! unitDefinitions.containsId(unit.getId())) {
+			unitDefinitions.add(unit);
+		}
+
+
 
 	}
 
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/fbc/FluxReaction.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/fbc/FluxReaction.java
index eeaab3eec226ddf636097fefb461cf955d26708c..f6ea5ae19125345298e9cc7599945d1d2ff6af49 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/fbc/FluxReaction.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/fbc/FluxReaction.java
@@ -138,13 +138,14 @@ public class FluxReaction extends BioEntity {
 			if (protlist.size() == 1) {
 				
 				BioProtein prot = protlist.iterator().next();
-				
-				BioEnzyme enz = new BioEnzyme(prot.getId(), prot.getName());
-				enz.setName(prot.getName());
-				
-				if(! bn.contains(enz)) {
+
+				BioEnzyme enz = bn.getEnzymesView().get(prot.getId());
+				if(enz == null)
+				{
+					enz = new BioEnzyme(prot.getId(), prot.getName());
 					bn.add(enz);
 				}
+
 				bn.affectSubUnit(enz, 1.0, prot);
 				
 				bn.affectEnzyme(rxn, enz);
@@ -152,10 +153,11 @@ public class FluxReaction extends BioEntity {
 			} else {
 				
 				String id = createIdFromProteins(protlist);
-				
-				BioEnzyme enz = new BioEnzyme(id, id);
-				
-				if(! bn.contains(enz)) {
+
+				BioEnzyme enz = bn.getEnzymesView().get(id);
+
+				if(enz == null) {
+					enz = new BioEnzyme(id, id);
 					bn.add(enz);
 				}
 				
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetwork.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetwork.java
index a8f1de190f46fffc199b83917576a9afb85bad38..570329394bccb932993911ec5ed3518cef196c21 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetwork.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetwork.java
@@ -59,7 +59,6 @@ import org.sbml.jsbml.UnitDefinition;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.compartment.BioCompartmentType;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.compartment.CompartmentAttributes;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.network.NetworkAttributes;
-import fr.inrae.toulouse.metexplore.met4j_io.annotations.reactant.ReactantAttributes;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.reaction.Flux;
 import fr.inrae.toulouse.metexplore.met4j_io.jsbml.attributes.SbmlAnnotation;
 import fr.inrae.toulouse.metexplore.met4j_io.jsbml.attributes.Notes;
@@ -78,637 +77,614 @@ import org.sbml.jsbml.Unit.Kind;
  * Abstract class that defines the different 'ListOf' parsing method.
  *
  * @author bmerlet
- * @since 3.0
  * @version $Id: $Id
+ * @since 3.0
  */
 public class JsbmlToBioNetwork {
 
-	/**
-	 * The {@link BioNetwork} created by this class
-	 */
-	private BioNetwork network;
+    /**
+     * The {@link BioNetwork} created by this class
+     */
+    private BioNetwork network;
+
+    private Model model;
+
+    /**
+     * The ordered list of {@link PackageParser} activated for this parser
+     */
+    public ArrayList<PackageParser> packages = new ArrayList<PackageParser>();
+
+    /**
+     * <p>Constructor for JsbmlToBioNetwork.</p>
+     *
+     * @param model a {@link org.sbml.jsbml.Model} object.
+     */
+    public JsbmlToBioNetwork(Model model) {
+        this.model = model;
+    }
+
+    /**
+     * Main method of the parser. It should call the different list parser defined
+     * in the inheriting classes
+     *
+     * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException if any.
+     */
+    protected void parseModel() throws Met4jSbmlReaderException {
+
+        this.parseNetworkData();
+        this.parseListOfUnitDefinitions();
+        this.parseListOfCompartments();
+
+        this.parseListOfSpecies();
+
+        this.parseListOfReactions();
+
+        this.parsePackageAdditionalData();
+    }
+
+    /**
+     * Parse the jsbml Model object and retrieves basic information from it
+     */
+    private void parseNetworkData() {
+
+        BioNetwork bionet = new BioNetwork(model.getId());
+
+        bionet.setName(model.getName());
+
+        this.setNetwork(bionet);
+    }
 
-	private Model model;
+    /**
+     * Default way of parsing sbml UnitDefinition. Needs to be overridden to modify
+     * behavior
+     */
+    private void parseListOfUnitDefinitions() {
 
-	/**
-	 * The ordered list of {@link PackageParser} activated for this parser
-	 */
-	public ArrayList<PackageParser> packages = new ArrayList<PackageParser>();
+        for (UnitDefinition jSBMLUD : model.getListOfUnitDefinitions()) {
 
-	/**
-	 * <p>Constructor for JsbmlToBioNetwork.</p>
-	 *
-	 * @param model a {@link org.sbml.jsbml.Model} object.
-	 */
-	public JsbmlToBioNetwork(Model model) {
-		this.model = model;
-	}
+            BioUnitDefinition bionetUD = new BioUnitDefinition(jSBMLUD.getId(), jSBMLUD.getName());
 
-	/**
-	 * Main method of the parser. It should call the different list parser defined
-	 * in the inheriting classes
-	 *
-	 * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException if any.
-	 */
-	protected void parseModel() throws Met4jSbmlReaderException {
+            if (jSBMLUD.getName().isEmpty()) {
+                bionetUD.setName(jSBMLUD.getId());
+            }
+            ListOf<Unit> listofunits = jSBMLUD.getListOfUnits();
 
-		this.parseNetworkData();
-		this.parseListOfUnitDefinitions();
-		this.parseListOfCompartments();
+            if (listofunits.size() != 0) {
 
-		this.parseListOfSpecies();
+                for (int n = 0; n < listofunits.size(); n++) {
 
-		this.parseListOfReactions();
+                    Unit jSBMLUnit = listofunits.get(n);
 
-		this.parsePackageAdditionalData();
-	}
+                    Kind kind = jSBMLUnit.getKind();
+                    Double Exp = jSBMLUnit.getExponent();
+                    Integer Scale = jSBMLUnit.getScale();
+                    Double Multiplier = jSBMLUnit.getMultiplier();
 
-	/**
-	 * Parse the jsbml Model object and retrieves basic information from it
-	 * 
-	 */
-	private void parseNetworkData() {
+                    UnitSbml bionetUnit = new UnitSbml(kind.getName(), Exp, Scale, Multiplier);
+                    bionetUD.addUnit(bionetUnit);
+                }
+            }
 
-		BioNetwork bionet = new BioNetwork(model.getId());
+            NetworkAttributes.addUnitDefinition(this.getNetwork(), bionetUD);
+        }
 
-		bionet.setName(model.getName());
+    }
 
-		this.setNetwork(bionet);
-	}
+    /**
+     * Default way of parsing sbml compartements. Needs to be overridden to modify
+     * behavior
+     */
+    private void parseListOfCompartments() {
 
-	/**
-	 * Default way of parsing sbml UnitDefinition. Needs to be overridden to modify
-	 * behavior
-	 * 
-	 */
-	private void parseListOfUnitDefinitions() {
+        if (model.getListOfCompartments().size() == 0) {
+            System.err.println("[WARNING] No compartment in the model !");
+        }
 
-		for (UnitDefinition jSBMLUD : model.getListOfUnitDefinitions()) {
+        for (Compartment jSBMLCompart : model.getListOfCompartments()) {
 
-			BioUnitDefinition bionetUD = new BioUnitDefinition(jSBMLUD.getId(), jSBMLUD.getName());
+            String compartId = jSBMLCompart.getId();
+            String compartName = jSBMLCompart.getName().trim();
 
-			if (jSBMLUD.getName().isEmpty()) {
-				bionetUD.setName(jSBMLUD.getId());
-			}
-			ListOf<Unit> listofunits = jSBMLUD.getListOfUnits();
+            if (StringUtils.isEmpty(compartName)) {
+                compartName = compartId;
+            }
 
-			if (listofunits.size() != 0) {
+            BioCompartment bionetCompart = this.getNetwork().getCompartmentsView().get(compartId);
+            if (bionetCompart == null) {
+                bionetCompart = new BioCompartment(compartId, compartName);
+                this.getNetwork().add(bionetCompart);
+            }
 
-				for (int n = 0; n < listofunits.size(); n++) {
+            /**
+             * SBML 2.0
+             */
+            if (jSBMLCompart.isSetCompartmentType()) {
+                BioCompartmentType type = new BioCompartmentType(
+                        model.getCompartmentType(jSBMLCompart.getCompartmentType()).getId(),
+                        model.getCompartmentType(jSBMLCompart.getCompartmentType()).getName());
+                CompartmentAttributes.setType(bionetCompart, type);
 
-					Unit jSBMLUnit = listofunits.get(n);
+            }
 
-					Kind kind = jSBMLUnit.getKind();
-					Double Exp = jSBMLUnit.getExponent();
-					Integer Scale = jSBMLUnit.getScale();
-					Double Multiplier = jSBMLUnit.getMultiplier();
+            /*
+             * If the compartment has an outside attribute, we need to look if the outside
+             * compartment exists in the bioNetwork
+             */
+            if (jSBMLCompart.isSetOutside()) {
 
-					UnitSbml bionetUnit = new UnitSbml(kind.getName(), Exp, Scale, Multiplier);
-					bionetUD.addUnit(bionetUnit);
-				}
-			}
+                Compartment outsideJSBMLComp = model.getCompartment(jSBMLCompart.getOutside());
 
-			NetworkAttributes.addUnitDefinition(this.getNetwork(), bionetUD);
-		}
+                BioCompartment outsideCompart = this.getNetwork().getCompartmentsView()
+                        .get(outsideJSBMLComp.getId());
 
-	}
+                // if it's null, we create it and add it to the bionetwork
+                if (outsideCompart == null) {
+                    outsideCompart = new BioCompartment(outsideJSBMLComp.getId(), outsideJSBMLComp.getName());
+                    this.getNetwork().add(outsideCompart);
+                }
 
-	/**
-	 * Default way of parsing sbml compartements. Needs to be overridden to modify
-	 * behavior
-	 * 
-	 */
-	private void parseListOfCompartments() {
+                // We can add it as outside compartment of the current
+                // compartment
+                CompartmentAttributes.setOutsideCompartment(bionetCompart, outsideCompart);
+            }
 
-		if(model.getListOfCompartments().size()==0)
-		{
-			System.err.println("[WARNING] No compartment in the model !");
-		}
+            if (jSBMLCompart.isSetUnits()) {
 
-		for (Compartment jSBMLCompart : model.getListOfCompartments()) {
+                UnitDefinition JsbmlUnitDef = model.getUnitDefinition(jSBMLCompart.getUnits());
+                BioUnitDefinition bionetUnitDef = NetworkAttributes.getUnitDefinition(this.getNetwork(),
+                        JsbmlUnitDef.getId());
+                CompartmentAttributes.setUnitDefinition(bionetCompart, bionetUnitDef);
+            }
 
-			String compartId = jSBMLCompart.getId();
-			String compartName = jSBMLCompart.getName().trim();
+            if (jSBMLCompart.getSBOTerm() != -1) {
+                CompartmentAttributes.setSboTerm(bionetCompart, jSBMLCompart.getSBOTermID());
+            }
 
-			if (StringUtils.isEmpty(compartName)) {
-				compartName = compartId;
-			}
+            CompartmentAttributes.setConstant(bionetCompart, jSBMLCompart.getConstant());
 
-			BioCompartment bionetCompart = this.getNetwork().getCompartmentsView().get(compartId);
-			if (bionetCompart == null) {
-				bionetCompart = new BioCompartment(compartId, compartName);
-				this.getNetwork().add(bionetCompart);
-			}
+            if (jSBMLCompart.isSetSize()) {
+                CompartmentAttributes.setSize(bionetCompart, jSBMLCompart.getSize());
+            }
 
-			/**
-			 * SBML 2.0
-			 */
-			if (jSBMLCompart.isSetCompartmentType()) {
-				BioCompartmentType type = new BioCompartmentType(
-						model.getCompartmentType(jSBMLCompart.getCompartmentType()).getId(),
-						model.getCompartmentType(jSBMLCompart.getCompartmentType()).getName());
-				CompartmentAttributes.setType(bionetCompart, type);
+            if (jSBMLCompart.isSetSpatialDimensions()) {
+                CompartmentAttributes.setSpatialDimensions(bionetCompart, (int) jSBMLCompart.getSpatialDimensions());
+            } else {
+                CompartmentAttributes.setSpatialDimensions(bionetCompart, 3);
+            }
 
-			}
+        }
 
-			/*
-			 * If the compartment has an outside attribute, we need to look if the outside
-			 * compartment exists in the bioNetwork
-			 */
-			if (jSBMLCompart.isSetOutside()) {
+    }
 
-				Compartment outsideJSBMLComp = model.getCompartment(jSBMLCompart.getOutside());
+    /**
+     * @return true if the parse contains the FBC package
+     */
+    private boolean containsFbcPackage() {
 
-				BioCompartment outsideCompart = this.getNetwork().getCompartmentsView()
-						.get(outsideJSBMLComp.getId());
+        for (PackageParser p : this.packages) {
+            if (p instanceof FBCParser) {
+                return true;
+            }
+        }
 
-				// if it's null, we create it and add it to the bionetwork
-				if (outsideCompart == null) {
-					outsideCompart = new BioCompartment(outsideJSBMLComp.getId(), outsideJSBMLComp.getName());
-					this.getNetwork().add(outsideCompart);
-				}
+        return false;
 
-				// We can add it as outside compartment of the current
-				// compartment
-				CompartmentAttributes.setOutsideCompartment(bionetCompart, outsideCompart);
-			}
+    }
 
-			if (jSBMLCompart.isSetUnits()) {
+    /**
+     * Method to parse the list of reaction of the jsbml model
+     *
+     * @throws Met4jSbmlReaderException
+     */
+    private void parseListOfReactions() throws Met4jSbmlReaderException {
 
-				UnitDefinition JsbmlUnitDef = model.getUnitDefinition(jSBMLCompart.getUnits());
-				BioUnitDefinition bionetUnitDef = NetworkAttributes.getUnitDefinition(this.getNetwork(),
-						JsbmlUnitDef.getId());
-				CompartmentAttributes.setUnitDefinition(bionetCompart, bionetUnitDef);
-			}
+        Boolean hasModifiers = false;
 
-			if (jSBMLCompart.getSBOTerm() != -1) {
-				CompartmentAttributes.setSboTerm(bionetCompart, jSBMLCompart.getSBOTermID());
-			}
+        for (Reaction jSBMLReaction : model.getListOfReactions()) {
+            String reactionId = jSBMLReaction.getId();
 
-			CompartmentAttributes.setConstant(bionetCompart, jSBMLCompart.getConstant());
+            String reactionName = jSBMLReaction.getName();
+            if (reactionName.isEmpty()) {
+                reactionName = reactionId;
+            }
+            BioReaction bionetReaction = new BioReaction(reactionId, reactionName);
 
-			if (jSBMLCompart.isSetSize()) {
-				CompartmentAttributes.setSize(bionetCompart, jSBMLCompart.getSize());
-			}
+            this.getNetwork().add(bionetReaction);
 
-			if (jSBMLCompart.isSetSpatialDimensions()) {
-				CompartmentAttributes.setSpatialDimensions(bionetCompart, (int) jSBMLCompart.getSpatialDimensions());
-			} else {
-				CompartmentAttributes.setSpatialDimensions(bionetCompart, 3);
-			}
+            if (jSBMLReaction.isSetSBOTerm()) {
+                ReactionAttributes.setSboTerm(bionetReaction, jSBMLReaction.getSBOTermID());
+            }
 
-		}
-
-	}
+            if (jSBMLReaction.isSetFast()
+                    && ((model.getLevel() < 3) || (model.getLevel() == 3 && model.getVersion() == 1))) {
+                ReactionAttributes.setFast(bionetReaction, jSBMLReaction.getFast());
+            }
 
-	/**
-	 * 
-	 * @return true if the parse contains the FBC package
-	 */
-	private boolean containsFbcPackage() {
+            // if reversible attribute is present and is set to false
+            if (jSBMLReaction.isSetReversible()) {
+                bionetReaction.setReversible(jSBMLReaction.getReversible());
+            } else {
+                bionetReaction.setReversible(true);
+            }
 
-		for (PackageParser p : this.packages) {
-			if (p instanceof FBCParser) {
-				return true;
-			}
-		}
+            this.parseReactionListOf(bionetReaction, jSBMLReaction.getListOfReactants(), "left");
+            this.parseReactionListOf(bionetReaction, jSBMLReaction.getListOfProducts(), "right");
 
-		return false;
-
-	}
+            BioUnitDefinitionCollection udList = NetworkAttributes.getUnitDefinitions(this.getNetwork());
 
-	/**
-	 * Method to parse the list of reaction of the jsbml model
-	 * 
-	 * @throws Met4jSbmlReaderException
-	 */
-	private void parseListOfReactions() throws Met4jSbmlReaderException {
+            KineticLaw kine = jSBMLReaction.getKineticLaw();
+            if (kine != null) {
 
-		Boolean hasModifiers = false;
+                ReactionAttributes.setKineticFormula(bionetReaction, kine.getMathMLString());
 
-		for (Reaction jSBMLReaction : model.getListOfReactions()) {
-			String reactionId = jSBMLReaction.getId();
+                if (model.getLevel() < 3) {
+                    for (int n = 0; n < kine.getNumParameters(); n++) {
 
-			String reactionName = jSBMLReaction.getName();
-			if (reactionName.isEmpty()) {
-				reactionName = reactionId;
-			}
-			BioReaction bionetReaction = new BioReaction(reactionId, reactionName);
+                        UnitDefinition jsbmlUnit = model.getUnitDefinition(kine.getParameter(n).getUnits());
 
-			this.getNetwork().add(bionetReaction);
+                        // This means that <parameter id="REDUCED_COST" value="0.000000"/> won't be taken into account
+                        if (jsbmlUnit != null) {
 
-			if (jSBMLReaction.isSetSBOTerm()) {
-				ReactionAttributes.setSboTerm(bionetReaction, jSBMLReaction.getSBOTermID());
-			}
+                            BioUnitDefinition UD = udList.get(jsbmlUnit.getId());
 
-			if (jSBMLReaction.isSetFast()
-					&& ((model.getLevel() < 3) || (model.getLevel() == 3 && model.getVersion() == 1))) {
-				ReactionAttributes.setFast(bionetReaction, jSBMLReaction.getFast());
-			}
+                            /**
+                             * This is to make sure that the unit definition associated with the fluxes is
+                             * not null, e.g dimensionless
+                             */
+                            if (UD == null) {
+                                UD = new BioUnitDefinition(jsbmlUnit.getId(), jsbmlUnit.getName());
+                                udList.add(UD);
+                            }
 
-			// if reversible attribute is present and is set to false
-			if (jSBMLReaction.isSetReversible()) {
-				bionetReaction.setReversible(jSBMLReaction.getReversible());
-			} else {
-				bionetReaction.setReversible(true);
-			}
+                            if (kine.getParameter(n).getId().equalsIgnoreCase("UPPER_BOUND")
+                                    || kine.getParameter(n).getName().equalsIgnoreCase("UPPER_BOUND")) {
 
-			this.parseReactionListOf(bionetReaction, jSBMLReaction.getListOfReactants(), "left");
-			this.parseReactionListOf(bionetReaction, jSBMLReaction.getListOfProducts(), "right");
+                                Flux newflux = new Flux(kine.getParameter(n).getId(), kine.getParameter(n).getValue(),
+                                        UD);
 
-			BioUnitDefinitionCollection udList = NetworkAttributes.getUnitDefinitions(this.getNetwork());
+                                try {
+                                    ReactionAttributes.setUpperBound(bionetReaction, newflux);
+                                } catch (IllegalArgumentException e) {
+                                    System.err.println("[Warning] Upper bound of reaction " + bionetReaction.getId() + " badly formatted : put to 0");
+                                    e.printStackTrace();
+                                    newflux.value = 0.0;
+                                    ReactionAttributes.setUpperBound(bionetReaction, newflux);
+                                }
 
-			KineticLaw kine = jSBMLReaction.getKineticLaw();
-			if (kine != null) {
+                            } else if (kine.getParameter(n).getId().equalsIgnoreCase("LOWER_BOUND")
+                                    || kine.getParameter(n).getName().equalsIgnoreCase("LOWER_BOUND")) {
 
-				ReactionAttributes.setKineticFormula(bionetReaction, kine.getMathMLString());
+                                Flux newflux = new Flux(kine.getParameter(n).getId(), kine.getParameter(n).getValue(),
+                                        UD);
 
-				if (model.getLevel() < 3) {
-					for (int n = 0; n < kine.getNumParameters(); n++) {
 
-						UnitDefinition jsbmlUnit = model.getUnitDefinition(kine.getParameter(n).getUnits());
+                                try {
+                                    ReactionAttributes.setLowerBound(bionetReaction, newflux);
+                                } catch (IllegalArgumentException e) {
+                                    System.err.println("[Warning] Lower bound of reaction " + bionetReaction.getId() + " badly formatted : put to 0");
+                                    e.printStackTrace();
+                                    newflux.value = 0.0;
+                                    ReactionAttributes.setLowerBound(bionetReaction, newflux);
+                                }
 
-						// This means that <parameter id="REDUCED_COST" value="0.000000"/> won't be taken into account
-						if (jsbmlUnit != null) {
+                            } else {
+                                Flux newflux = new Flux(kine.getParameter(n).getId(), kine.getParameter(n).getValue(),
+                                        UD);
 
-							BioUnitDefinition UD = udList.get(jsbmlUnit.getId());
+                                ReactionAttributes.addFlux(bionetReaction, newflux);
+
+                            }
+                        }
 
-							/**
-							 * This is to make sure that the unit definition associated with the fluxes is
-							 * not null, e.g dimensionless
-							 */
-							if (UD == null) {
-								UD = new BioUnitDefinition(jsbmlUnit.getId(), jsbmlUnit.getName());
-								udList.add(UD);
-							}
+                    }
+                } else if (!this.containsFbcPackage()) { // SBML V3.0 and not
+                    // fbc package
 
-							if (kine.getParameter(n).getId().equalsIgnoreCase("UPPER_BOUND")
-									|| kine.getParameter(n).getName().equalsIgnoreCase("UPPER_BOUND")) {
+                    for (LocalParameter param : kine.getListOfLocalParameters()) {
+
+                        UnitDefinition jsbmlUnit = model.getUnitDefinition(param.getUnits());
+                        if (jsbmlUnit == null) {
+                            throw new Met4jSbmlReaderException("Problem with the reaction " + bionetReaction.getId()
+                                    + " : the flux unit " + param.getUnits() + " does not exist in the model");
+                        } else {
 
-								Flux newflux = new Flux(kine.getParameter(n).getId(), kine.getParameter(n).getValue(),
-										UD);
+                            BioUnitDefinition UD = udList.get(jsbmlUnit.getId());
+
+                            /**
+                             * This is to make sure that the unit definition associated with the fluxes is
+                             * not null
+                             */
+                            if (UD == null) {
+                                UD = new BioUnitDefinition(jsbmlUnit.getId(), jsbmlUnit.getName());
+                                udList.add(UD);
+                            }
+
+                            if (param.getId().equalsIgnoreCase("UPPER_BOUND")
+                                    || param.getName().equalsIgnoreCase("UPPER_BOUND")) {
+
+                                String name = "UPPER_BOUND";
+                                Flux newflux = new Flux(name, param.getValue(), UD);
+                                ReactionAttributes.setUpperBound(bionetReaction, newflux);
 
-								try {
-									ReactionAttributes.setUpperBound(bionetReaction, newflux);
-								} catch (IllegalArgumentException e) {
-									System.err.println("[Warning] Upper bound of reaction "+bionetReaction.getId()+ " badly formatted : put to 0");
-									e.printStackTrace();
-									newflux.value = 0.0;
-									ReactionAttributes.setUpperBound(bionetReaction, newflux);
-								}
+                            } else if (param.getId().equalsIgnoreCase("LOWER_BOUND")
+                                    || param.getName().equalsIgnoreCase("LOWER_BOUND")) {
 
-							} else if (kine.getParameter(n).getId().equalsIgnoreCase("LOWER_BOUND")
-									|| kine.getParameter(n).getName().equalsIgnoreCase("LOWER_BOUND")) {
-
-								Flux newflux = new Flux(kine.getParameter(n).getId(), kine.getParameter(n).getValue(),
-										UD);
-
-
-								try {
-									ReactionAttributes.setLowerBound(bionetReaction, newflux);
-								} catch (IllegalArgumentException e) {
-									System.err.println("[Warning] Lower bound of reaction "+bionetReaction.getId()+ " badly formatted : put to 0");
-									e.printStackTrace();
-									newflux.value = 0.0;
-									ReactionAttributes.setLowerBound(bionetReaction, newflux);
-								}
-
-							} else {
-								Flux newflux = new Flux(kine.getParameter(n).getId(), kine.getParameter(n).getValue(),
-										UD);
-
-								ReactionAttributes.addFlux(bionetReaction, newflux);
-
-							}
-						}
+                                String name = "LOWER_BOUND";
+                                Flux newflux = new Flux(name, param.getValue(), UD);
+                                ReactionAttributes.setLowerBound(bionetReaction, newflux);
 
-					}
-				} else if (!this.containsFbcPackage()) { // SBML V3.0 and not
-															// fbc package
+                            } else {
+                                Flux newflux = new Flux(param.getId(), param.getValue(), UD);
+
+                                ReactionAttributes.addFlux(bionetReaction, newflux);
+
+                            }
+                        }
+                    }
+
+                }
+            }
+
+            if (jSBMLReaction.getModifierCount() > 0) {
+                hasModifiers = true;
+            }
+
+        }
+
+        if (hasModifiers) {
+            System.err.println("[warning] Some reactions have list of modifiers. Be careful, Met4j-io does not import list of modifiers");
+        }
+    }
 
-					for (LocalParameter param : kine.getListOfLocalParameters()) {
-
-						UnitDefinition jsbmlUnit = model.getUnitDefinition(param.getUnits());
-						if (jsbmlUnit == null) {
-							throw new Met4jSbmlReaderException("Problem with the reaction " + bionetReaction.getId()
-									+ " : the flux unit " + param.getUnits() + " does not exist in the model");
-						} else {
-
-							BioUnitDefinition UD = udList.get(jsbmlUnit.getId());
-
-							/**
-							 * This is to make sure that the unit definition associated with the fluxes is
-							 * not null
-							 */
-							if (UD == null) {
-								UD = new BioUnitDefinition(jsbmlUnit.getId(), jsbmlUnit.getName());
-								udList.add(UD);
-							}
-
-							if (param.getId().equalsIgnoreCase("UPPER_BOUND")
-									|| param.getName().equalsIgnoreCase("UPPER_BOUND")) {
-
-								String name = "UPPER_BOUND";
-								Flux newflux = new Flux(name, param.getValue(), UD);
-								ReactionAttributes.setUpperBound(bionetReaction, newflux);
-
-							} else if (param.getId().equalsIgnoreCase("LOWER_BOUND")
-									|| param.getName().equalsIgnoreCase("LOWER_BOUND")) {
-
-								String name = "LOWER_BOUND";
-								Flux newflux = new Flux(name, param.getValue(), UD);
-								ReactionAttributes.setLowerBound(bionetReaction, newflux);
-
-							} else {
-								Flux newflux = new Flux(param.getId(), param.getValue(), UD);
-
-								ReactionAttributes.addFlux(bionetReaction, newflux);
-
-							}
-						}
-					}
-
-				}
-			}
-
-			if(jSBMLReaction.getModifierCount() > 0)
-			{
-				hasModifiers = true;
-			}
-
-		}
-
-		if(hasModifiers)
-		{
-			System.err.println("[warning] Some reactions have list of modifiers. Be careful, Met4j-io does not import list of modifiers");
-		}
-	}
-
-	/**
-	 * Abstract class to parse the list of SpeciesReferences of a given Reaction
-	 * 
-	 * @param bionetReaction the {@link BioReaction}
-	 * @param listOf         the jsbml list of SpeciesReferences
-	 * @param side           The side of the SpeciesReferences
-	 *                       <ul>
-	 *                       <li>left = reactants
-	 *                       <li>right = products
-	 *                       </ul>
-	 */
-	private void parseReactionListOf(BioReaction bionetReaction, ListOf<SpeciesReference> listOf, String side) {
-		for (SpeciesReference specieRef : listOf) {
-			BioReactant reactant = this.parseParticipantSpecies(specieRef);
-
-			if(reactant != null) {
-				if (specieRef.isSetConstant()) {
-					ReactantAttributes.setConstant(reactant, specieRef.getConstant());
-				}
-
-				if (side.equals("left")) {
-					this.getNetwork().affectLeft(bionetReaction, reactant);
-				} else {
-					this.getNetwork().affectRight(bionetReaction, reactant);
-				}
-			}
-
-		}
-	}
-
-	private void parseListOfSpecies() {
-
-		Boolean hasInvalidSboTerms = false;
-
-		for (Species specie : this.getModel().getListOfSpecies()) {
-			String specieId = specie.getId();
-
-			String specieName = specie.getName();
-			if (specieName.isEmpty()) {
-				specieName = specieId;
-			}
-
-			// Check if the sbo term is valid for a metabolite
-			Boolean validSboTerm = true;
-			String sboTerm =  specie.getSBOTermID();
-
-			if(sboTerm != null)
-			{
-				if(sboTerm.compareToIgnoreCase("SBO:0000252")==0)
-				{
-					validSboTerm = false;
-					hasInvalidSboTerms = true;
-					// It's considered as a gene
-					// We replace the first "_" by "" if exists
-
-					String oldId = specieId;
-
-					specieId = specieId.replaceFirst("^_", "");
-					specieId = specieId.replaceFirst("_.$", "");
-					specieName = specieName.replaceFirst("^_", "");
-					specieName = specieName.replaceFirst("_.$", "");
-					BioGene gene = new BioGene(specieId, specieName);
-
-					gene.setAttribute("oldId", oldId);
-
-					this.getNetwork().add(gene);
-				}
-				else if(sboTerm.compareToIgnoreCase("SBO:0000014")==0 || sboTerm.compareToIgnoreCase("SBO:0000297")==0)
-				{
-					validSboTerm = false;
-					hasInvalidSboTerms = true;
-
-					String oldId = specieId;
-					// It's considered as an enzyme
-					specieId = specieId.replaceFirst("^_", "");
-					specieId = specieId.replaceFirst("_.$", "");
-					specieName = specieName.replaceFirst("^_", "");
-					specieName = specieName.replaceFirst("_.$", "");
-					BioEnzyme enz = new BioEnzyme(specieId, specieName);
-
-					enz.setAttribute("oldId", oldId);
-
-					this.getNetwork().add(enz);
-				}
-			}
-
-			if(validSboTerm) {
-
-				BioMetabolite bionetSpecies = new BioMetabolite(specieId, specieName);
-
-				MetaboliteAttributes.setBoundaryCondition(bionetSpecies, specie.getBoundaryCondition());
-				MetaboliteAttributes.setConstant(bionetSpecies, specie.getConstant());
-
-				MetaboliteAttributes.setSubstanceUnits(bionetSpecies, specie.getSubstanceUnits());
-				if (specie.getSBOTerm() != -1) {
-					MetaboliteAttributes.setSboTerm(bionetSpecies, specie.getSBOTermID());
-				}
-
-				if (specie.isSetInitialAmount()) {
-					MetaboliteAttributes.setInitialAmount(bionetSpecies, specie.getInitialAmount());
-				} else if (specie.isSetInitialConcentration()) {
-					MetaboliteAttributes.setInitialConcentration(bionetSpecies, specie.getInitialConcentration());
-				}
-
-				if (specie.isSetCharge()) {
-					bionetSpecies.setCharge(specie.getCharge());
-				}
-
-				MetaboliteAttributes.setSubstanceUnits(bionetSpecies, specie.getSubstanceUnits());
-
-				if (model.getLevel() == 2 && model.getVersion() >= 2 && model.getVersion() <= 4) {
-					if (specie.isSetSpeciesType()) {
-
-						SpeciesType stype = specie.getSpeciesTypeInstance();
-						if (stype.isSetSBOTerm()) {
-
-							MetaboliteAttributes.setSboTerm(bionetSpecies, stype.getSBOTermID());
-
-						}
-						try {
-							if (stype.isSetAnnotation()) {
-								MetaboliteAttributes.setAnnotation(bionetSpecies,
-										new SbmlAnnotation(stype.getId(), stype.getAnnotationString()));
-							}
-							if (stype.isSetNotes()) {
-								MetaboliteAttributes.setNotes(bionetSpecies, new Notes(stype.getNotesString()));
-							}
-						} catch (XMLStreamException e) {
-							e.printStackTrace();
-						}
-					}
-				}
-
-				this.getNetwork().add(bionetSpecies);
-
-				this.getNetwork().affectToCompartment(
-						this.getNetwork().getCompartmentsView().get(specie.getCompartment()), bionetSpecies);
-			}
-		}
-
-		if(hasInvalidSboTerms)
-		{
-			System.err.println("[warning] Sbo term for some species are not metabolite sbo terms, they haven't been imported or have been imported as genes, " +
-					"depending on their sbo term (SBO:0000252) or as enzymes (SBO:0000014 or SBO:0000297).");
-		}
-	}
-
-	/**
-	 * parse the jsbml species participating in a reaction and create the
-	 * corresponding metabolite
-	 */
-	private BioReactant parseParticipantSpecies(SpeciesReference specieRef) {
-		Species specie = this.getModel().getSpecies(specieRef.getSpecies());
-		if(specie == null)
-		{
-			throw new IllegalArgumentException("The specie "+specieRef.getSpecies()+ " does not exist");
-		}
-		
-		String specieId = specie.getId();
-
-		Double stoDbl = specieRef.getStoichiometry();
-
-		if(Double.isNaN(stoDbl) || Double.isInfinite(stoDbl)) {
-			System.err.println("Warning : invalid coefficient : " + stoDbl + " for " + specieId+": set to 1.0");
-			stoDbl = 1.0;
-		}
-
-		if(stoDbl < 0)
-		{
-			System.err.println("Warning : negative coefficient : " + stoDbl + " for " + specieId+" : set to positive");
-			stoDbl = -stoDbl;
-		}
-
-		if(stoDbl == 0)
-		{
-			System.err.println("Warning : coefficient equals to 0 for " + specieId+" : This reactant won't be added to the reaction");
-			stoDbl = -stoDbl;
-		}
-
-		BioReactant reactant = null;
-
-		if(stoDbl != 0) {
-			BioMetabolite bionetSpecies = this.getNetwork().getMetabolitesView().get(specieId);
-
-			reactant = new BioReactant(bionetSpecies, stoDbl,
-					this.getNetwork().getCompartmentsView().get(specie.getCompartment()));
-		}
-
-		return reactant;
-	}
-
-	/**
-	 * <p>Getter for the field <code>network</code>.</p>
-	 *
-	 * @return the bionet
-	 */
-	public BioNetwork getNetwork() {
-		return network;
-	}
-
-	/**
-	 * <p>Setter for the field <code>network</code>.</p>
-	 *
-	 * @param bionet the bionet to set
-	 */
-	public void setNetwork(BioNetwork bionet) {
-		this.network = bionet;
-	}
-
-	/**
-	 * <p>getSetOfPackage.</p>
-	 *
-	 * @return the setOfPackage
-	 */
-	public ArrayList<PackageParser> getSetOfPackage() {
-		return packages;
-	}
-
-	/**
-	 * Add a package to this parser
-	 *
-	 * @param pkg the package to add
-	 * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.errors.JSBMLPackageReaderException if any.
-	 */
-	public void addPackage(PackageParser pkg) throws JSBMLPackageReaderException {
-
-		if ((this.getModel().getLevel() <= 2 && pkg instanceof ReaderSBML2Compatible)
-				|| (this.getModel().getLevel() > 2 && pkg instanceof ReaderSBML3Compatible)) {
-			this.getSetOfPackage().add(pkg);
-		} else {
-			throw new JSBMLPackageReaderException("Invalid SBML level and package Reader combination");
-		}
-
-	}
-
-	/**
-	 * Set the {@link #packages} to a new list
-	 *
-	 * @param packages the ordered list of packages to set
-	 * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.errors.JSBMLPackageReaderException if any.
-	 */
-	public void setPackages(ArrayList<PackageParser> packages) throws JSBMLPackageReaderException {
-		for (PackageParser pkg : packages) {
-			this.addPackage(pkg);
-		}
-	}
-
-	/**
-	 * Launch the parsing of the jsbml model by the different packages
-	 *
-	 * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException if any.
-	 */
-	public void parsePackageAdditionalData() throws Met4jSbmlReaderException {
-		for (PackageParser parser : this.getSetOfPackage()) {
-			parser.parseModel(model, this.getNetwork());
-		}
-	}
-
-	/**
-	 * <p>Getter for the field <code>model</code>.</p>
-	 *
-	 * @return a {@link org.sbml.jsbml.Model} object.
-	 */
-	public Model getModel() {
-		return model;
-	}
+    /**
+     * Abstract class to parse the list of SpeciesReferences of a given Reaction
+     *
+     * @param bionetReaction the {@link BioReaction}
+     * @param listOf         the jsbml list of SpeciesReferences
+     * @param side           The side of the SpeciesReferences
+     *                       <ul>
+     *                       <li>left = reactants
+     *                       <li>right = products
+     *                       </ul>
+     */
+    private void parseReactionListOf(BioReaction bionetReaction, ListOf<SpeciesReference> listOf, String side) {
+        for (SpeciesReference specieRef : listOf) {
+           this.parseParticipantSpecies(bionetReaction, specieRef, side);
+        }
+    }
+
+    private void parseListOfSpecies() {
+
+        Boolean hasInvalidSboTerms = false;
+
+        for (Species specie : this.getModel().getListOfSpecies()) {
+            String specieId = specie.getId();
+
+            String specieName = specie.getName();
+            if (specieName.isEmpty()) {
+                specieName = specieId;
+            }
+
+            // Check if the sbo term is valid for a metabolite
+            Boolean validSboTerm = true;
+            String sboTerm = specie.getSBOTermID();
+
+            if (sboTerm != null) {
+                if (sboTerm.compareToIgnoreCase("SBO:0000252") == 0) {
+                    validSboTerm = false;
+                    hasInvalidSboTerms = true;
+                    // It's considered as a gene
+                    // We replace the first "_" by "" if exists
+
+                    String oldId = specieId;
+
+                    specieId = specieId.replaceFirst("^_", "");
+                    specieId = specieId.replaceFirst("_.$", "");
+                    specieName = specieName.replaceFirst("^_", "");
+                    specieName = specieName.replaceFirst("_.$", "");
+                    BioGene gene = new BioGene(specieId, specieName);
+
+                    gene.setAttribute("oldId", oldId);
+
+                    this.getNetwork().add(gene);
+                } else if (sboTerm.compareToIgnoreCase("SBO:0000014") == 0 || sboTerm.compareToIgnoreCase("SBO:0000297") == 0) {
+                    validSboTerm = false;
+                    hasInvalidSboTerms = true;
+
+                    String oldId = specieId;
+                    // It's considered as an enzyme
+                    specieId = specieId.replaceFirst("^_", "");
+                    specieId = specieId.replaceFirst("_.$", "");
+                    specieName = specieName.replaceFirst("^_", "");
+                    specieName = specieName.replaceFirst("_.$", "");
+                    BioEnzyme enz = new BioEnzyme(specieId, specieName);
+
+                    enz.setAttribute("oldId", oldId);
+
+                    this.getNetwork().add(enz);
+                }
+            }
+
+            if (validSboTerm) {
+
+                BioMetabolite bionetSpecies = new BioMetabolite(specieId, specieName);
+
+                MetaboliteAttributes.setBoundaryCondition(bionetSpecies, specie.getBoundaryCondition());
+                MetaboliteAttributes.setConstant(bionetSpecies, specie.getConstant());
+
+                MetaboliteAttributes.setSubstanceUnits(bionetSpecies, specie.getSubstanceUnits());
+                if (specie.getSBOTerm() != -1) {
+                    MetaboliteAttributes.setSboTerm(bionetSpecies, specie.getSBOTermID());
+                }
+
+                if (specie.isSetInitialAmount()) {
+                    MetaboliteAttributes.setInitialAmount(bionetSpecies, specie.getInitialAmount());
+                } else if (specie.isSetInitialConcentration()) {
+                    MetaboliteAttributes.setInitialConcentration(bionetSpecies, specie.getInitialConcentration());
+                }
+
+                if (specie.isSetCharge()) {
+                    bionetSpecies.setCharge(specie.getCharge());
+                }
+
+                MetaboliteAttributes.setSubstanceUnits(bionetSpecies, specie.getSubstanceUnits());
+
+                if (model.getLevel() == 2 && model.getVersion() >= 2 && model.getVersion() <= 4) {
+                    if (specie.isSetSpeciesType()) {
+
+                        SpeciesType stype = specie.getSpeciesTypeInstance();
+                        if (stype.isSetSBOTerm()) {
+
+                            MetaboliteAttributes.setSboTerm(bionetSpecies, stype.getSBOTermID());
+
+                        }
+                        try {
+                            if (stype.isSetAnnotation()) {
+                                MetaboliteAttributes.setAnnotation(bionetSpecies,
+                                        new SbmlAnnotation(stype.getId(), stype.getAnnotationString()));
+                            }
+                            if (stype.isSetNotes()) {
+                                MetaboliteAttributes.setNotes(bionetSpecies, new Notes(stype.getNotesString()));
+                            }
+                        } catch (XMLStreamException e) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+
+                this.getNetwork().add(bionetSpecies);
+
+                this.getNetwork().affectToCompartment(
+                        this.getNetwork().getCompartmentsView().get(specie.getCompartment()), bionetSpecies);
+            }
+        }
+
+        if (hasInvalidSboTerms) {
+            System.err.println("[warning] Sbo term for some species are not metabolite sbo terms, they haven't been imported or have been imported as genes, " +
+                    "depending on their sbo term (SBO:0000252) or as enzymes (SBO:0000014 or SBO:0000297).");
+        }
+    }
+
+    /**
+     * parse the jsbml species participating in a reaction and create the
+     * corresponding metabolite
+     */
+    private void parseParticipantSpecies(BioReaction reaction, SpeciesReference specieRef, String side) {
+        Species specie = this.getModel().getSpecies(specieRef.getSpecies());
+        if (specie == null) {
+            throw new IllegalArgumentException("The specie " + specieRef.getSpecies() + " does not exist");
+        }
+
+        String specieId = specie.getId();
+
+        Double stoDbl = specieRef.getStoichiometry();
+
+        if (Double.isNaN(stoDbl) || Double.isInfinite(stoDbl)) {
+            System.err.println("Warning : invalid coefficient : " + stoDbl + " for " + specieId + ": set to 1.0");
+            stoDbl = 1.0;
+        }
+
+        if (stoDbl < 0) {
+            System.err.println("Warning : negative coefficient : " + stoDbl + " for " + specieId + " : set to positive");
+            stoDbl = -stoDbl;
+        }
+
+        if (stoDbl == 0) {
+            System.err.println("Warning : coefficient equals to 0 for " + specieId + " : This reactant won't be added to the reaction");
+            stoDbl = -stoDbl;
+        }
+
+
+        if (stoDbl != 0) {
+            BioMetabolite bionetSpecies = this.getNetwork().getMetabolitesView().get(specieId);
+
+            if (side.equals("left")) {
+                this.network.affectLeft(reaction, stoDbl,
+                        this.getNetwork().getCompartmentsView().get(specie.getCompartment()),
+                        bionetSpecies);
+            }
+            else {
+                this.network.affectRight(reaction, stoDbl,
+                        this.getNetwork().getCompartmentsView().get(specie.getCompartment()),
+                        bionetSpecies);
+            }
+        }
+    }
+
+    /**
+     * <p>Getter for the field <code>network</code>.</p>
+     *
+     * @return the bionet
+     */
+    public BioNetwork getNetwork() {
+        return network;
+    }
+
+    /**
+     * <p>Setter for the field <code>network</code>.</p>
+     *
+     * @param bionet the bionet to set
+     */
+    public void setNetwork(BioNetwork bionet) {
+        this.network = bionet;
+    }
+
+    /**
+     * <p>getSetOfPackage.</p>
+     *
+     * @return the setOfPackage
+     */
+    public ArrayList<PackageParser> getSetOfPackage() {
+        return packages;
+    }
+
+    /**
+     * Add a package to this parser
+     *
+     * @param pkg the package to add
+     * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.errors.JSBMLPackageReaderException if any.
+     */
+    public void addPackage(PackageParser pkg) throws JSBMLPackageReaderException {
+
+        if ((this.getModel().getLevel() <= 2 && pkg instanceof ReaderSBML2Compatible)
+                || (this.getModel().getLevel() > 2 && pkg instanceof ReaderSBML3Compatible)) {
+            this.getSetOfPackage().add(pkg);
+        } else {
+            throw new JSBMLPackageReaderException("Invalid SBML level and package Reader combination");
+        }
+
+    }
+
+    /**
+     * Set the {@link #packages} to a new list
+     *
+     * @param packages the ordered list of packages to set
+     * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.errors.JSBMLPackageReaderException if any.
+     */
+    public void setPackages(ArrayList<PackageParser> packages) throws JSBMLPackageReaderException {
+        for (PackageParser pkg : packages) {
+            this.addPackage(pkg);
+        }
+    }
+
+    /**
+     * Launch the parsing of the jsbml model by the different packages
+     *
+     * @throws fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException if any.
+     */
+    public void parsePackageAdditionalData() throws Met4jSbmlReaderException {
+        for (PackageParser parser : this.getSetOfPackage()) {
+            parser.parseModel(model, this.getNetwork());
+        }
+    }
+
+    /**
+     * <p>Getter for the field <code>model</code>.</p>
+     *
+     * @return a {@link org.sbml.jsbml.Model} object.
+     */
+    public Model getModel() {
+        return model;
+    }
 
 }
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/kegg/Kegg2BioNetwork.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/kegg/Kegg2BioNetwork.java
index a50cfa5ec06c69552b5beb2a730a94c5bd387b9a..eeb7b34c1b3ba3da95ca780f481b462b51af59a1 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/kegg/Kegg2BioNetwork.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/kegg/Kegg2BioNetwork.java
@@ -319,10 +319,27 @@ public class Kegg2BioNetwork {
                         for (String longGeneId : genes) {
 
                             String geneId = this.simplifyId(longGeneId);
-                            BioGene gene = new BioGene(geneId);
-                            BioProtein prot = new BioProtein(geneId);
-                            BioEnzyme enz = new BioEnzyme(geneId);
-                            network.add(gene, prot, enz);
+
+                            BioGene gene = network.getGenesView().get(geneId);
+                            if(gene == null)
+                            {
+                                gene = new BioGene(geneId);
+                                network.add(gene);
+                            }
+
+                            BioProtein prot = network.getProteinsView().get(geneId);
+                            if(prot == null)
+                            {
+                                prot = new BioProtein(geneId);
+                                network.add(prot);
+                            }
+
+                            BioEnzyme enz = network.getEnzymesView().get(geneId);
+                            if(enz == null) {
+                                enz = new BioEnzyme(geneId);
+                                network.add(enz);
+                            }
+
                             network.affectGeneProduct(prot, gene);
                             network.affectSubUnit(enz, 1.0, prot);
                             network.affectEnzyme(reaction, enz);
@@ -346,19 +363,14 @@ public class Kegg2BioNetwork {
                                     this.network.affectToCompartment(cpt, cpd);
                                 }
                                 if (child.getNodeName().equalsIgnoreCase("substrate")) {
-                                    BioReactant lpart = new BioReactant(cpd, 1.0, cpt);
-                                    ReactionAttributes.setConstant(lpart, false);
-                                    network.affectLeft(reaction, lpart);
+                                    network.affectLeft(reaction, 1.0, cpt, cpd);
                                     continue;
                                 }
-                                BioReactant rpart = new BioReactant(cpd, 1.0, cpt);
-                                ReactionAttributes.setConstant(rpart, false);
-                                network.affectRight(reaction, rpart);
+                                network.affectRight(reaction, 1.0, cpt, cpd);
                             }
                         }
 
                     }
-
                     network.affectToPathway(pathway, reaction);
                 }
             }
@@ -397,7 +409,7 @@ public class Kegg2BioNetwork {
      * @param substrateAndStoichio a String containing the coefficient (optional) and the cpd id
      * @return a {@link BioReactant}
      */
-    private BioReactant createReactant(String substrateAndStoichio, String reactionId) {
+    private void createReactant(String substrateAndStoichio, BioReaction reaction, Boolean rightSide) {
         String stoichio;
         String longCpdId;
         BioMetabolite cpd;
@@ -413,7 +425,7 @@ public class Kegg2BioNetwork {
             if (m.find()) {
                 // The stoichio is in the form 2n, we keep only 2.
                 stoichio = m.group(1);
-                System.err.println("[met4j-io][Kegg2BioNetwork] Warning: in reaction " + reactionId +
+                System.err.println("[met4j-io][Kegg2BioNetwork] Warning: in reaction " + reaction.getId() +
                         " : changes the stoichiometric coefficient from " + tmp[0] + " to " + stoichio);
             }
             longCpdId = tmp[1];
@@ -426,7 +438,7 @@ public class Kegg2BioNetwork {
         // Here we remove patterns like (n), (n +1)
         if (longCpdId.matches(".*\\([^)]+\\)$")) {
             String id2 = longCpdId.replaceAll("\\([^)]+\\)", "");
-            System.err.println("[met4j-io][Kegg2BioNetwork] Warning: in reaction " + reactionId +
+            System.err.println("[met4j-io][Kegg2BioNetwork] Warning: in reaction " + reaction.getId() +
                     " : changes the id from " + longCpdId + " to " + id2);
             longCpdId = id2;
         }
@@ -446,10 +458,17 @@ public class Kegg2BioNetwork {
             coeff = Double.parseDouble(stoichio);
         } catch (NumberFormatException e) {
             System.err.println("[met4j-io][Kegg2BioNetwork] Warning :  The stoechiometry "
-                    + stoichio + " in the reaction " + reactionId + " is not a number, it is left as 1.0");
+                    + stoichio + " in the reaction " + reaction.getId() + " is not a number, it is left as 1.0");
+        }
+
+        if(! rightSide){
+            this.network.affectLeft(reaction, coeff, cpt, cpd);
+        }
+        else {
+            this.network.affectRight(reaction, coeff, cpt, cpd);
         }
 
-        return new BioReactant(cpd, coeff, cpt);
+        return;
     }
 
     /**
@@ -518,13 +537,11 @@ public class Kegg2BioNetwork {
                 String[] prod = eq[1].split(" \\+ ");
 
                 for (String substrateAndStoichio : subs) {
-                    BioReactant lPart = createReactant(substrateAndStoichio, id);
-                    network.affectLeft(rxn, lPart);
+                    createReactant(substrateAndStoichio, rxn, false);
                 }
 
                 for (String productAndStoechio : prod) {
-                    BioReactant rPart = createReactant(productAndStoechio, id);
-                    network.affectRight(rxn, rPart);
+                    createReactant(productAndStoechio, rxn, true);
                 }
             }
             if (Data.get("ENZYME") != null) {
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/AbstractSetAttributesFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/AbstractSetAttributesFromFile.java
index bde071692b8ee18b2a9034409de09f011618ace5..3a34207d426e1da8a09027092e736b8cdecdeb74 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/AbstractSetAttributesFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/AbstractSetAttributesFromFile.java
@@ -50,6 +50,7 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+
 /**
  * <p>Abstract AbstractSetAttributesFromFile class.</p>
  *
@@ -58,101 +59,79 @@ import java.util.regex.Pattern;
  */
 public abstract class AbstractSetAttributesFromFile {
 
-    private int colId = 0;
-    private int colAttr = 1;
-    private BioNetwork bn;
-    private String fileIn;
-    private String commentCharacter = "#";
-    private int nSkip = 0;
-    private String object = REACTION;
-    private Boolean addPrefix = false;
-    private Boolean addSuffix = false;
+    protected int colId = 0;
+    protected int colAttr = 1;
+    protected BioNetwork bn;
+    protected String fileIn;
+    protected String commentCharacter = "#";
+    protected int nSkip = 0;
+    protected EntityType entityType = EntityType.REACTION;
+    protected Boolean addPrefix = false;
+    protected Boolean addSuffix = false;
 
-    private Set<String> ids;
+    protected Set<String> ids;
 
-    /**
-     * Constant <code>REACTION="R"</code>
-     */
-    public static final String REACTION = "R";
-    /**
-     * Constant <code>METABOLITE="M"</code>
-     */
-    public static final String METABOLITE = "M";
-    /**
-     * Constant <code>PROTEIN="P"</code>
-     */
-    public static final String PROTEIN = "P";
-    /**
-     * Constant <code>GENE="G"</code>
-     */
-    public static final String GENE = "G";
-    /**
-     * Constant <code>PATHWAY="Pa"</code>
-     */
-    public static final String PATHWAY = "Pa";
-
-    private Set<String> objectIds;
+    protected Set<String> objectIds;
 
-    private HashMap<String, String> idAttributeMap;
+    protected HashMap<String, String> idAttributeMap;
 
     /**
      * <p>Constructor for AbstractSetAttributesFromFile.</p>
      *
-     * @param colAttr : number of the attribute column
-     * @param bn      : BioNetwork
-     * @param fileIn  : tabulated file containing the ids and the attributes
-     * @param c       : comment character
-     * @param o       : object to set ("R" : reaction, "M" : metabolite, "G" : gene,
-     *                "P" : protein, "PA" : pathway)
-     * @param p       a {@link java.lang.Boolean} object.
-     * @param nSkip   a int.
-     * @param s       a {@link java.lang.Boolean} object.
-     * @param colId   a int.
+     * @param colId      a int.
+     * @param colAttr    : number of the attribute column
+     * @param bn         : BioNetwork
+     * @param fileIn     : tabulated file containing the ids and the attributes
+     * @param c          : comment character
+     * @param nSkip      a int.
+     * @param entityType a {@link EntityType}
+     * @param p          a {@link Boolean} object.
+     * @param s          a {@link Boolean} object.
      */
-    public AbstractSetAttributesFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, String o,
+    public AbstractSetAttributesFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, EntityType entityType,
                                          Boolean p, Boolean s) {
 
-        this.setColId(colId);
-        this.setColAttr(colAttr);
-        this.setNetwork(bn);
-        this.setFileIn(fileIn);
-        this.setCommentCharacter(c);
-        this.setnSkip(nSkip);
-        this.setAddPrefix(p);
-        this.setAddSuffix(s);
-        this.setIdAttributeMap(new HashMap<String, String>());
+        this.colId = colId;
+        this.colAttr = colAttr;
+        this.bn = bn;
+        this.fileIn = fileIn;
+        this.commentCharacter = c;
+        this.nSkip = nSkip;
+        this.addPrefix = p;
+        this.addSuffix = s;
+        this.idAttributeMap = new HashMap<>();
         this.ids = new HashSet<>();
 
-        if (!o.equalsIgnoreCase(REACTION) && !o.equalsIgnoreCase(METABOLITE) && !o.equalsIgnoreCase(PROTEIN)
-                && !o.equalsIgnoreCase(GENE) && !o.equalsIgnoreCase(PATHWAY)) {
-            System.err.println("Bad identifier of object : " + o);
-            System.err.println("Identifiers allowed : " + REACTION + " (reaction) " + METABOLITE + " (metabolite) "
-                    + PROTEIN + " (protein) " + GENE + " (gene) " + PATHWAY + " (pathway)");
-            System.err.println(REACTION + " is defined as default");
-        } else {
-            this.setObject(o);
-        }
+        this.entityType = entityType;
 
-        if (this.getObject().equalsIgnoreCase(REACTION)) {
+        if (this.entityType.equals(EntityType.REACTION)) {
             this.objectIds = bn.getReactionsView().getIds();
         }
 
-        if (this.getObject().equalsIgnoreCase(METABOLITE)) {
+        if (this.entityType.equals(EntityType.METABOLITE)) {
             this.objectIds = bn.getMetabolitesView().getIds();
         }
 
-        if (this.getObject().equalsIgnoreCase(PROTEIN)) {
+        if (this.entityType.equals(EntityType.PROTEIN)) {
             this.objectIds = bn.getProteinsView().getIds();
         }
 
-        if (this.getObject().equalsIgnoreCase(GENE)) {
+        if (this.entityType.equals(EntityType.GENE)) {
             this.objectIds = bn.getGenesView().getIds();
         }
 
-        if (this.getObject().equalsIgnoreCase(PATHWAY)) {
+        if (this.entityType.equals(EntityType.PATHWAY)) {
             this.objectIds = bn.getPathwaysView().getIds();
         }
 
+        if (this.colId < 0) {
+            throw new IllegalArgumentException("The id column number must be positive");
+        }
+
+        if (this.colAttr < 0) {
+            throw new IllegalArgumentException("The attribute column number must be positive");
+        }
+
     }
 
     /**
@@ -161,22 +140,14 @@ public abstract class AbstractSetAttributesFromFile {
      * @return a {@link java.lang.Boolean} object.
      * @throws java.io.IOException if any.
      */
-    public Boolean test() throws IOException {
+    public Boolean parseAttributeFile() throws IOException {
 
         Boolean flag = true;
 
-        if (this.colId < 0) {
-            System.err.println("There is an error in the id column number");
-        }
-
-        if (this.colAttr < 0) {
-            System.err.println("There is an error in the attribute column number");
-        }
-
         FileInputStream in;
         BufferedReader br;
         try {
-            in = new FileInputStream(this.getFileIn());
+            in = new FileInputStream(this.fileIn);
             InputStreamReader ipsr = new InputStreamReader(in);
             br = new BufferedReader(ipsr);
         } catch (Exception e) {
@@ -194,17 +165,7 @@ public abstract class AbstractSetAttributesFromFile {
 
             flag = parseLine(ligne, nLines);
         }
-
-        br.close();
-
-        if (flag == false) {
-            System.err.println("Input file badly formatted");
-        } else {
-            System.err.println("The input file looks good and contains " + ids.size() + " entries");
-        }
-
         return flag;
-
     }
 
     protected Boolean parseLine(String line, int nLines) {
@@ -213,17 +174,26 @@ public abstract class AbstractSetAttributesFromFile {
 
         line = line.replace("\n", "").replace("\r", "");
 
-        if ((nLines > this.nSkip) && (! line.isEmpty())
-                && (this.getCommentCharacter().equals("")
-                || !line.matches("^" + this.getCommentCharacter() + ".*"))) {
+        if ((nLines > this.nSkip) && (!line.isEmpty())
+                && (this.commentCharacter.equals("")
+                || !line.matches("^" + this.commentCharacter + ".*"))) {
 
             String[] tab = line.split("\\t");
 
-            if (tab.length <= this.colId || tab.length <= this.colAttr) {
-                System.err
-                        .println("********\n[Error]Bad number of columns line " + nLines + "\n********");
-                flag = false;
-            } else {
+            // We do not return an error if the length of the tab
+            // is less than the column index because when the final columns are empty,
+            // the split does not take into account them
+
+            Pattern pattern = Pattern.compile("\\t");
+            Matcher matcher = pattern.matcher(line);
+            long nbColumns = matcher.results().count() + 1;
+
+            if (nbColumns <= this.colId || nbColumns <= this.colAttr) {
+                System.err.println("********\n[Warning] Bad number of columns line " + nLines + "(" + nbColumns + ")\n********");
+                return false;
+            }
+
+            if (tab.length > this.colId && tab.length > this.colAttr) {
 
                 String attribute = tab[this.colAttr];
 
@@ -237,7 +207,7 @@ public abstract class AbstractSetAttributesFromFile {
                 // remove spaces
                 id = id.trim();
 
-                if (this.getObject().equalsIgnoreCase(METABOLITE)) {
+                if (this.entityType.equals(EntityType.METABOLITE)) {
                     // To transform metabolite id like this cpd[c] in
                     // cpd_c
                     Pattern cpd_Pattern = Pattern.compile("^.*(\\[([^\\]]*)\\])$");
@@ -250,10 +220,10 @@ public abstract class AbstractSetAttributesFromFile {
                     }
                 }
 
-                if (this.getObject().equalsIgnoreCase(METABOLITE) && this.addSuffix) {
+                if (this.entityType.equals(EntityType.METABOLITE) && this.addSuffix) {
                     Boolean presence = false;
 
-                    BioCollection<BioCompartment> compartmentsView = this.getNetwork().getCompartmentsView();
+                    BioCollection<BioCompartment> compartmentsView = this.bn.getCompartmentsView();
                     // Checks if the suffix corresponds to a compartment
                     for (String compartmentId : compartmentsView.getIds()) {
 
@@ -280,7 +250,7 @@ public abstract class AbstractSetAttributesFromFile {
                         // +metaboliteId;
                         // }
 
-                        if (this.getNetwork().getMetabolitesView().containsId(metaboliteId)) {
+                        if (this.bn.getMetabolitesView().containsId(metaboliteId)) {
                             this.getIdAttributeMap().put(metaboliteId, attribute);
                             presence = true;
                         }
@@ -303,10 +273,10 @@ public abstract class AbstractSetAttributesFromFile {
                 } else {
 //							id = id.replaceAll("[^A-Za-z0-9_]", "_");
 
-                    if (this.addPrefix && this.object.equalsIgnoreCase(REACTION)) {
+                    if (this.addPrefix && this.entityType.equals(EntityType.REACTION)) {
                         if (!id.startsWith("R_"))
                             id = "R_" + id;
-                    } else if (this.addPrefix && this.object.equalsIgnoreCase(METABOLITE)) {
+                    } else if (this.addPrefix && this.entityType.equals(EntityType.METABOLITE)) {
                         if (!id.startsWith("M_"))
                             id = "M_" + id;
                     }
@@ -352,150 +322,6 @@ public abstract class AbstractSetAttributesFromFile {
      */
     public abstract Boolean setAttributes() throws IOException;
 
-    /**
-     * <p>Getter for the field <code>colId</code>.</p>
-     *
-     * @return the colId
-     */
-    public int getColId() {
-        return colId;
-    }
-
-    /**
-     * <p>Setter for the field <code>colId</code>.</p>
-     *
-     * @param colId the colId to set
-     */
-    public void setColId(int colId) {
-        this.colId = colId;
-    }
-
-    /**
-     * <p>Getter for the field <code>colAttr</code>.</p>
-     *
-     * @return the colAttr
-     */
-    public int getColAttr() {
-        return colAttr;
-    }
-
-    /**
-     * <p>Setter for the field <code>colAttr</code>.</p>
-     *
-     * @param colAttr the colAttr to set
-     */
-    public void setColAttr(int colAttr) {
-        this.colAttr = colAttr;
-    }
-
-    /**
-     * <p>getNetwork.</p>
-     *
-     * @return the network
-     */
-    public BioNetwork getNetwork() {
-        return bn;
-    }
-
-    /**
-     * <p>setNetwork.</p>
-     *
-     * @param bn the network to set
-     */
-    public void setNetwork(BioNetwork bn) {
-        this.bn = bn;
-    }
-
-    /**
-     * <p>Getter for the field <code>fileIn</code>.</p>
-     *
-     * @return the fileIn
-     */
-    public String getFileIn() {
-        return fileIn;
-    }
-
-    /**
-     * <p>Setter for the field <code>fileIn</code>.</p>
-     *
-     * @param fileIn the fileIn to set
-     */
-    public void setFileIn(String fileIn) {
-        this.fileIn = fileIn;
-    }
-
-    /**
-     * <p>Getter for the field <code>commentCharacter</code>.</p>
-     *
-     * @return the commentCharacter
-     */
-    public String getCommentCharacter() {
-        return commentCharacter;
-    }
-
-    /**
-     * <p>Setter for the field <code>commentCharacter</code>.</p>
-     *
-     * @param commentCharacter the commentCharacter to set
-     */
-    public void setCommentCharacter(String commentCharacter) {
-        this.commentCharacter = commentCharacter;
-    }
-
-    /**
-     * <p>Getter for the field <code>nSkip</code>.</p>
-     *
-     * @return the nSkip
-     */
-    public int getnSkip() {
-        return nSkip;
-    }
-
-    /**
-     * <p>Setter for the field <code>nSkip</code>.</p>
-     *
-     * @param nSkip the nSkip to set
-     */
-    public void setnSkip(int nSkip) {
-        this.nSkip = nSkip;
-    }
-
-    /**
-     * <p>Getter for the field <code>object</code>.</p>
-     *
-     * @return the object
-     */
-    public String getObject() {
-        return object;
-    }
-
-    /**
-     * <p>Setter for the field <code>object</code>.</p>
-     *
-     * @param object the object to set
-     */
-    public void setObject(String object) {
-        this.object = object;
-    }
-
-    /**
-     * <p>Setter for the field <code>addPrefix</code>.</p>
-     *
-     * @param p a {@link java.lang.Boolean} object.
-     */
-    public void setAddPrefix(Boolean p) {
-        this.addPrefix = p;
-    }
-
-    /**
-     * <p>Setter for the field <code>addSuffix</code>.</p>
-     *
-     * @param s a {@link java.lang.Boolean} object.
-     */
-    public void setAddSuffix(Boolean s) {
-        this.addSuffix = s;
-    }
-
     /**
      * <p>Getter for the field <code>idAttributeMap</code>.</p>
      *
@@ -505,32 +331,4 @@ public abstract class AbstractSetAttributesFromFile {
         return idAttributeMap;
     }
 
-    /**
-     * <p>Setter for the field <code>idAttributeMap</code>.</p>
-     *
-     * @param idAttributeMap the idAttributeMap to set
-     */
-    public void setIdAttributeMap(HashMap<String, String> idAttributeMap) {
-        this.idAttributeMap = idAttributeMap;
-    }
-
-    /**
-     * <p>Getter for the field <code>addPrefix</code>.</p>
-     *
-     * @return a {@link java.lang.Boolean} object.
-     */
-    public Boolean getAddPrefix() {
-        return addPrefix;
-    }
-
-    /**
-     * <p>Getter for the field <code>addSuffix</code>.</p>
-     *
-     * @return a {@link java.lang.Boolean} object.
-     */
-    public Boolean getAddSuffix() {
-        return addSuffix;
-    }
-
-
 }
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/reactant/ReactantAttributes.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/EntityType.java
similarity index 59%
rename from met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/reactant/ReactantAttributes.java
rename to met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/EntityType.java
index 479c12b4bb1125973e86612d006bc949432b6f4e..8b2ee8d9697b0e4364c24d26b54ad1583dd68b29 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/reactant/ReactantAttributes.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/EntityType.java
@@ -1,5 +1,5 @@
 /*
- * Copyright INRAE (2020)
+ * Copyright INRAE (2022)
  *
  * contact-metexplore@inrae.fr
  *
@@ -33,43 +33,8 @@
  * knowledge of the CeCILL license and that you accept its terms.
  *
  */
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
 
-package fr.inrae.toulouse.metexplore.met4j_io.annotations.reactant;
-
-import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant;
-import fr.inrae.toulouse.metexplore.met4j_io.annotations.GenericAttributes;
-
-/**
- * <p>ReactantAttributes class.</p>
- *
- * @author lcottret
- * @version $Id: $Id
- */
-public class ReactantAttributes extends GenericAttributes {
-	/** Constant <code>IS_COFACTOR="is_cofactor"</code> */
-	public static final String IS_COFACTOR = "is_cofactor";
-	
-	/**
-	 * get is cofactor attribute
-	 *
-	 * @param reactant a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant} object.
-	 * @return a {@link java.lang.Boolean} object.
-	 */
-	public static Boolean getIsCofactor(BioReactant reactant) {
-		if(reactant.getAttribute(IS_COFACTOR) == null) {
-			return false;
-		}
-		return (Boolean) reactant.getAttribute(IS_COFACTOR);
-
-	}
-	
-	/**
-	 * Set IsCofactor value
-	 *
-	 * @param reactant a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant} object.
-	 * @param b a boolean.
-	 */
-	public static void setIsCofactor(BioReactant reactant, boolean b) {
-		reactant.setAttribute(IS_COFACTOR, b);
-	}
+public enum EntityType {
+    REACTION, METABOLITE, GENE, PROTEIN, PATHWAY
 }
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFile.java
index b7c4741015425224a6eb538f7f7bdb16de4c627a..953ad109bb82a011b45564c2352b13a845b3523e 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFile.java
@@ -53,7 +53,7 @@ public class SetBoundsFromFile extends AbstractSetAttributesFromFile {
     private BoundsType type;
 
     public SetBoundsFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, BoundsType type) {
-        super(colId, colAttr, bn, fileIn, c, nSkip, REACTION, p, false);
+        super(colId, colAttr, bn, fileIn, c, nSkip, EntityType.REACTION, p, false);
         this.type = type;
     }
 
@@ -78,12 +78,12 @@ public class SetBoundsFromFile extends AbstractSetAttributesFromFile {
      * @return a {@link java.lang.Boolean} object.
      * @throws java.io.IOException if any.
      */
-    public Boolean setAttributes() throws IOException {
+    public Boolean setAttributes() {
 
-        Boolean flag = true;
+        Boolean flag;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             return false;
         }
@@ -97,7 +97,7 @@ public class SetBoundsFromFile extends AbstractSetAttributesFromFile {
         for(String id : this.getIdAttributeMap().keySet()) {
             n++;
             Double bound = Double.parseDouble(this.getIdAttributeMap().get(id));
-            BioReaction r = this.getNetwork().getReactionsView().get(id);
+            BioReaction r = this.bn.getReactionsView().get(id);
             if(this.type.equals(BoundsType.LOWER)) {
                 ReactionAttributes.setLowerBound(r, new Flux(bound));
             }
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetChargesFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetChargesFromFile.java
index 47e08ea297a5b794e6af26b7cda7608742ce5996..30615a88aa3f428d4561c03452b13752bdacbd38 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetChargesFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetChargesFromFile.java
@@ -37,7 +37,6 @@
 package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
 
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
-import fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils;
 
 import java.io.IOException;
 
@@ -52,35 +51,44 @@ public class SetChargesFromFile extends AbstractSetAttributesFromFile {
     /**
      * <p>Constructor for SetChargesFromFile.</p>
      *
-     * @param colId a int.
+     * @param colId   a int.
      * @param colAttr a int.
-     * @param bn a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork} object.
-     * @param fileIn a {@link java.lang.String} object.
-     * @param c a {@link java.lang.String} object.
-     * @param nSkip a int.
-     * @param p a {@link java.lang.Boolean} object.
-     * @param s a {@link java.lang.Boolean} object.
+     * @param bn      a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork} object.
+     * @param fileIn  a {@link java.lang.String} object.
+     * @param c       a {@link java.lang.String} object.
+     * @param nSkip   a int.
+     * @param p       a {@link java.lang.Boolean} object.
+     * @param s       a {@link java.lang.Boolean} object.
      */
     public SetChargesFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s) {
 
-        super(colId, colAttr, bn, fileIn, c, nSkip, "M", p, s);
+        super(colId, colAttr, bn, fileIn, c, nSkip, EntityType.METABOLITE, p, s);
 
     }
 
     /**
      * {@inheritDoc}
-     *
+     * <p>
      * Test the charge
      */
     public Boolean testAttribute(String charge) {
-        if(StringUtils.isInteger(charge)) {
-            return true;
+
+        Boolean flag = true;
+
+        try {
+            Double val = Double.parseDouble(charge);
+            if(val%1 != 0) {
+                flag = false;
+            }
+        } catch (NumberFormatException e) {
+            flag = false;
         }
-        else {
-            System.err.println(charge+ " no in good format (integer)");
-            return false;
+
+        if(! flag) {
+            System.err.println("Error : the charge " + charge + " is not an integer");
         }
 
+        return flag;
     }
 
     /**
@@ -89,38 +97,39 @@ public class SetChargesFromFile extends AbstractSetAttributesFromFile {
      * @return a {@link java.lang.Boolean} object.
      * @throws java.io.IOException if any.
      */
-    public Boolean setAttributes() throws IOException {
+    public Boolean setAttributes() {
 
-        Boolean flag = true;
+        Boolean flag;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             return false;
         }
 
-        if(!flag) {
+        if (!flag) {
             return false;
         }
 
         int n = 0;
 
-        for(String id : this.getIdAttributeMap().keySet()) {
+        for (String id : this.getIdAttributeMap().keySet()) {
 
             n++;
 
             String charge = this.getIdAttributeMap().get(id);
 
-            try {
-                this.getNetwork().getMetabolitesView().get(id).setCharge(Integer.parseInt(charge));
-            } catch (NumberFormatException e) {
-                System.err.println("Warning : the charge + \""+charge+"\" for the metabolite "+id+" is not an integer");
+            if(this.testAttribute(charge)) {
+                Double dbl = Double.parseDouble(charge);
+                this.bn.getMetabolitesView().get(id).setCharge(dbl.intValue());
+            }
+            else {
+                System.err.println("Warning : the charge + \"" + charge + "\" for the metabolite " + id + " is not an integer");
             }
-
         }
 
 
-        System.err.println(n+" attributions");
+        System.err.println(n + " attributions");
 
         return flag;
 
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetEcsFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetEcsFromFile.java
index 44991c87f520c40e3c68a40da132418b022fa6a3..17a618ecd7f377f999231cc049c12f425415e178 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetEcsFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetEcsFromFile.java
@@ -39,6 +39,9 @@ package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
 
 import java.io.IOException;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 /**
  * <p>SetEcsFromFile class.</p>
@@ -47,32 +50,48 @@ import java.io.IOException;
  * @version $Id: $Id
  */
 public class SetEcsFromFile extends AbstractSetAttributesFromFile {
+    private final Pattern patternEC;
+
     /**
      * <p>Constructor for SetEcsFromFile.</p>
      *
-     * @param colId number of the column where are the reaction ids
+     * @param colId   number of the column where are the reaction ids
      * @param colAttr number of the column where are the gpr
-     * @param bn BioNetwork
-     * @param fileIn tabulated file
-     * @param c comment string
-     * @param nSkip number of lines to skip at the beginning of the file
-     * @param p if true, to match the reactions in the sbml file, the reaction ids in the tabulated file are formatted in the palsson way
-     * @param s a {@link java.lang.Boolean} object.
+     * @param bn      BioNetwork
+     * @param fileIn  tabulated file
+     * @param c       comment string
+     * @param nSkip   number of lines to skip at the beginning of the file
+     * @param p       if true, to match the reactions in the sbml file, the reaction ids in the tabulated file are formatted in the palsson way
+     * @param s       a {@link java.lang.Boolean} object.
      */
     public SetEcsFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s) {
 
-        super(colId, colAttr, bn, fileIn, c, nSkip, REACTION, p, s);
+        super(colId, colAttr, bn, fileIn, c, nSkip, EntityType.REACTION, p, s);
+
+        patternEC = Pattern.compile("(EC\\s*)*\\d{1}(\\.(\\d{0,3}|-)){0,3}");
 
     }
 
     /**
      * {@inheritDoc}
-     *
+     * <p>
      * Test the ec
-     * TODO : to complete
      */
     public Boolean testAttribute(String ec) {
-        return true;
+        if (ec.isEmpty())
+            return true;
+
+        if(ec.endsWith(";"))
+            return false;
+
+        String[] ecs = ec.split(";");
+
+        System.err.println("ec : "+ec+" l :"+ecs.length);
+
+        return Arrays.stream(ecs).allMatch(e -> {
+            Matcher m = patternEC.matcher(e);
+            return m.matches();
+        });
     }
 
     /**
@@ -86,28 +105,30 @@ public class SetEcsFromFile extends AbstractSetAttributesFromFile {
         Boolean flag = true;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             return false;
         }
 
-        if(!flag) {
+        if (!flag) {
             return false;
         }
 
         int n = 0;
 
-        for(String id : this.getIdAttributeMap().keySet()) {
+        for (String id : this.getIdAttributeMap().keySet()) {
 
             n++;
 
-            String EC = this.getIdAttributeMap().get(id);
+            String ec = this.getIdAttributeMap().get(id);
 
-            this.getNetwork().getReactionsView().get(id).setEcNumber(EC);
+            if(! ec.isEmpty()) {
+                this.bn.getReactionsView().get(id).setEcNumber(ec);
+            }
 
         }
 
-        System.err.println(n+" reactions processed");
+        System.err.println(n + " reactions processed");
 
         return flag;
 
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetFormulasFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetFormulasFromFile.java
index effd5d5b3bc799fbd9b346e3e725d8d34770fc3e..e1f86bcfe43f8665429588eb9e0fb2ab640390b8 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetFormulasFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetFormulasFromFile.java
@@ -37,6 +37,7 @@
 package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
 
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils;
 
 import java.io.IOException;
 
@@ -62,7 +63,7 @@ public class SetFormulasFromFile extends AbstractSetAttributesFromFile {
      */
     public SetFormulasFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s) {
 
-        super(colId, colAttr, bn, fileIn, c, nSkip, "M", p, s);
+        super(colId, colAttr, bn, fileIn, c, nSkip, EntityType.METABOLITE, p, s);
 
     }
 
@@ -72,7 +73,11 @@ public class SetFormulasFromFile extends AbstractSetAttributesFromFile {
      * Test the name
      */
     public Boolean testAttribute(String formula) {
-        return true;
+        if(formula.isEmpty()) {
+            return true;
+        }
+
+        return StringUtils.checkMetaboliteFormula(formula);
     }
 
     /**
@@ -86,7 +91,7 @@ public class SetFormulasFromFile extends AbstractSetAttributesFromFile {
         Boolean flag = true;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             return false;
         }
@@ -103,7 +108,7 @@ public class SetFormulasFromFile extends AbstractSetAttributesFromFile {
 
             String formula = this.getIdAttributeMap().get(id);
 
-            this.getNetwork().getMetabolitesView().get(id).setChemicalFormula(formula);
+            this.bn.getMetabolitesView().get(id).setChemicalFormula(formula);
 
         }
 
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetGprsFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetGprsFromFile.java
index f44322bfcc6e810cdf1963f251240dd542795d9d..26e4ff946b43ea641e82ac8ddf26e68b273985c9 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetGprsFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetGprsFromFile.java
@@ -40,7 +40,6 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.gpr.GPR;
-import fr.inrae.toulouse.metexplore.met4j_io.jsbml.errors.MalformedGeneAssociationStringException;
 
 import java.io.IOException;
 
@@ -66,7 +65,7 @@ public class SetGprsFromFile extends AbstractSetAttributesFromFile {
      */
     public SetGprsFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s) {
 
-        super(colId, colAttr, bn, fileIn, c, nSkip, REACTION, p, s);
+        super(colId, colAttr, bn, fileIn, c, nSkip, EntityType.REACTION, p, s);
 
     }
 
@@ -92,7 +91,7 @@ public class SetGprsFromFile extends AbstractSetAttributesFromFile {
         Boolean flag = true;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             e.printStackTrace();
             return false;
@@ -103,7 +102,7 @@ public class SetGprsFromFile extends AbstractSetAttributesFromFile {
         }
 
 
-        BioCollection<BioReaction> reactionsView = this.getNetwork().getReactionsView();
+        BioCollection<BioReaction> reactionsView = this.bn.getReactionsView();
 
         for(String id : this.getIdAttributeMap().keySet()) {
 
@@ -112,7 +111,7 @@ public class SetGprsFromFile extends AbstractSetAttributesFromFile {
             String gpr = this.getIdAttributeMap().get(id);
 
             try {
-                GPR.createGPRfromString(this.getNetwork(), reaction, gpr);
+                GPR.createGPRfromString(this.bn, reaction, gpr);
             } catch (Exception e) {
                 e.printStackTrace();
                 System.err.println("GPR badly formatted for reaction "+reaction.getId());
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetNamesFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetNamesFromFile.java
index 4747c0090360750591e0d9ace63378bcde64633e..7f66c2ed2be57693cdd0da487824078ddda05907 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetNamesFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetNamesFromFile.java
@@ -37,7 +37,6 @@
 package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
 
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity;
-import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
 
 import java.io.IOException;
@@ -61,11 +60,11 @@ public class SetNamesFromFile extends AbstractSetAttributesFromFile {
      * @param nSkip a int.
      * @param p a {@link java.lang.Boolean} object.
      * @param s a {@link java.lang.Boolean} object.
-     * @param object a {@link java.lang.String} object.
+     * @param entityType a {@link EntityType} object.
      */
-    public SetNamesFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s, String object) {
+    public SetNamesFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s, EntityType entityType) {
 
-        super(colId, colAttr, bn, fileIn, c, nSkip, object, p, s);
+        super(colId, colAttr, bn, fileIn, c, nSkip, entityType, p, s);
 
     }
 
@@ -89,7 +88,7 @@ public class SetNamesFromFile extends AbstractSetAttributesFromFile {
         Boolean flag = true;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             return false;
         }
@@ -108,20 +107,20 @@ public class SetNamesFromFile extends AbstractSetAttributesFromFile {
 
             String name = this.getIdAttributeMap().get(id);
 
-            if(this.getObject().equalsIgnoreCase(METABOLITE)) {
-                object = this.getNetwork().getMetabolitesView().get(id);
+            if(this.entityType.equals(EntityType.METABOLITE)) {
+                object = this.bn.getMetabolitesView().get(id);
             }
-            else if(this.getObject().equalsIgnoreCase(GENE)) {
-                object = this.getNetwork().getGenesView().get(id);
+            else if(this.entityType.equals(EntityType.GENE)) {
+                object = this.bn.getGenesView().get(id);
             }
-            else if(this.getObject().equalsIgnoreCase(PROTEIN)) {
-                object = this.getNetwork().getProteinsView().get(id);
+            else if(this.entityType.equals(EntityType.PROTEIN)) {
+                object = this.bn.getProteinsView().get(id);
             }
-            else if(this.getObject().equalsIgnoreCase(PATHWAY)) {
-                object = this.getNetwork().getPathwaysView().get(id);
+            else if(this.entityType.equals(EntityType.PATHWAY)) {
+                object = this.bn.getPathwaysView().get(id);
             }
             else {
-                object = this.getNetwork().getReactionsView().get(id);
+                object = this.bn.getReactionsView().get(id);
             }
 
             object.setName(name);
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetPathwaysFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetPathwaysFromFile.java
index f38a7f317816b82d2d2ae9233279c5117789030e..faaaa5000cb76e264fa6eb51199557f2dc8d839e 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetPathwaysFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetPathwaysFromFile.java
@@ -78,7 +78,7 @@ public class SetPathwaysFromFile extends AbstractSetAttributesFromFile {
      */
     public SetPathwaysFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s, String sep) {
 
-        super(colId, colAttr, bn, fileIn, c, nSkip, REACTION, p, s);
+        super(colId, colAttr, bn, fileIn, c, nSkip, EntityType.REACTION, p, s);
 
         this.sep = sep;
     }
@@ -103,7 +103,7 @@ public class SetPathwaysFromFile extends AbstractSetAttributesFromFile {
         Boolean flag = true;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             return false;
         }
@@ -129,12 +129,12 @@ public class SetPathwaysFromFile extends AbstractSetAttributesFromFile {
 
             String[] pathwayIds = pathwayIdsStr.split(Pattern.quote(sep));
 
-            BioReaction rxn = this.getNetwork().getReactionsView().get(id);
+            BioReaction rxn = this.bn.getReactionsView().get(id);
 
-            BioCollection<BioPathway> oldPathways = this.getNetwork().getPathwaysFromReaction(rxn);
+            BioCollection<BioPathway> oldPathways = this.bn.getPathwaysFromReaction(rxn);
 
             for(BioPathway p : oldPathways) {
-                this.getNetwork().removeReactionFromPathway(rxn, p);
+                this.bn.removeReactionFromPathway(rxn, p);
             }
 
             for (int i = 0; i < pathwayIds.length; i++) {
@@ -145,13 +145,13 @@ public class SetPathwaysFromFile extends AbstractSetAttributesFromFile {
                 pathwayId = pathwayId.replaceAll("[^A-Za-z0-9_-]", "_");
 
                 BioPathway pathway;
-                if (this.getNetwork().getPathwaysView().containsId(pathwayId)) {
-                    pathway = this.getNetwork().getPathwaysView().get(pathwayId);
+                if (this.bn.getPathwaysView().containsId(pathwayId)) {
+                    pathway = this.bn.getPathwaysView().get(pathwayId);
                 } else {
                     pathway = new BioPathway(pathwayId);
-                    this.getNetwork().add(pathway);
+                    this.bn.add(pathway);
                 }
-                this.getNetwork().affectToPathway(pathway, rxn);
+                this.bn.affectToPathway(pathway, rxn);
             }
         }
 
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetRefsFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetRefsFromFile.java
index cb0ba72bc817d4721c849e9115e279e54461dfaf..c0572f52d2bdeb942c628e48753de2fb146155a7 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetRefsFromFile.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetRefsFromFile.java
@@ -39,7 +39,6 @@ package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioRef;
-import fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils;
 import fr.inrae.toulouse.metexplore.met4j_io.refs.IdentifiersOrg;
 
 import java.io.IOException;
@@ -66,17 +65,17 @@ public class SetRefsFromFile extends AbstractSetAttributesFromFile {
      * @param p a {@link java.lang.Boolean} object.
      * @param s a {@link java.lang.Boolean} object.
      * @param ref a {@link java.lang.String} object.
-     * @param type a {@link java.lang.String} object.
+     * @param entityType a {@link EntityType} object.
      */
-    public SetRefsFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s, String ref, String type) {
-        super(colId, colAttr, bn, fileIn, c, nSkip, type, p, s);
+    public SetRefsFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, Boolean p, Boolean s, String ref, EntityType entityType) {
+        super(colId, colAttr, bn, fileIn, c, nSkip, entityType, p, s);
 
         this.ref = ref;
 
     }
 
     /** {@inheritDoc} */
-    public Boolean testAttribute(String charge) {
+    public Boolean testAttribute(String attribute) {
         return true;
     }
 
@@ -91,7 +90,7 @@ public class SetRefsFromFile extends AbstractSetAttributesFromFile {
         Boolean flag = true;
 
         try {
-            flag = this.test();
+            flag = this.parseAttributeFile();
         } catch (IOException e) {
             return false;
         }
@@ -103,7 +102,7 @@ public class SetRefsFromFile extends AbstractSetAttributesFromFile {
         int n = 0;
 
         if(! IdentifiersOrg.validIdentifiers.contains(ref)) {
-            System.err.println("Warning : the identifier "+ref+" is not a valid id in identifiers.org, it will appear only in SBML notes");
+            System.err.println("Warning : the identifier "+ref+" is not a valid id in identifiers.org");
         }
 
         for(String id : this.getIdAttributeMap().keySet()) {
@@ -112,20 +111,20 @@ public class SetRefsFromFile extends AbstractSetAttributesFromFile {
             BioEntity object;
             n++;
 
-            if(this.getObject().equalsIgnoreCase(METABOLITE)) {
-                object = this.getNetwork().getMetabolitesView().get(id);
+            if(this.entityType.equals(EntityType.METABOLITE)) {
+                object = this.bn.getMetabolitesView().get(id);
             }
-            else if(this.getObject().equalsIgnoreCase(GENE)) {
-                object = this.getNetwork().getGenesView().get(id);
+            else if(this.entityType.equals(EntityType.GENE)) {
+                object = this.bn.getGenesView().get(id);
             }
-            else if(this.getObject().equalsIgnoreCase(PROTEIN)) {
-                object = this.getNetwork().getProteinsView().get(id);
+            else if(this.entityType.equals(EntityType.PROTEIN)) {
+                object = this.bn.getProteinsView().get(id);
             }
-            else if(this.getObject().equalsIgnoreCase(PATHWAY)) {
-                object = this.getNetwork().getPathwaysView().get(id);
+            else if(this.entityType.equals(EntityType.PATHWAY)) {
+                object = this.bn.getPathwaysView().get(id);
             }
             else {
-                object = this.getNetwork().getReactionsView().get(id);
+                object = this.bn.getReactionsView().get(id);
             }
 
             object.addRef(new BioRef("attributesTable", this.ref, this.getIdAttributeMap().get(id), 1));
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/BioNetwork2Tab.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/BioNetwork2Tab.java
index 06fe02247b61a066841ff1722b92558852acc7ba..63f2160cae77a505925db58bc4a30d4375527327 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/BioNetwork2Tab.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/BioNetwork2Tab.java
@@ -84,35 +84,40 @@ public class BioNetwork2Tab {
     public void write() throws IOException {
 
         FileWriter fw = new FileWriter(this.outputFile);
-
         fw.write("#Id\tName\tFormulaIds\tFormulaNames\tEC\tpathways\tgpr\tlb\tub\n");
-
         /**
          * For ordering reactions in the file and thus making easy the tests and the versioning
          */
         TreeMap<String, BioReaction> reactions = new TreeMap<String, BioReaction>(
                 this.network.getReactionsView().getMapView());
 
-
         for(BioReaction r : reactions.values()) {
-
-            String name = r.getName();
-            String formulaIds = BioReactionUtils.getEquation(r, false, revSep, irrevSep, true);
-            String formulaNames =BioReactionUtils.getEquation(r, true, revSep, irrevSep, true);
-            String ec = r.getEcNumber() == null ? "NA" : r.getEcNumber();
-            String pathways = BioReactionUtils.getPathwaysString(r, this.network,true, " ; ");
-            String gpr = BioReactionUtils.getGPR(this.network, r);
-            Flux lowerBound = ReactionAttributes.getLowerBound(r);
-            String lb = lowerBound != null ? lowerBound.value.toString() : "NA";
-            Flux upperBound = ReactionAttributes.getUpperBound(r);
-            String ub = upperBound != null ? upperBound.value.toString() : "NA";
-
-            fw.write(r.getId()+"\t"+name+"\t"+formulaIds+"\t"+formulaNames+"\t"+ec+"\t"
-                    + pathways + "\t" + gpr + "\t" + lb + "\t" +ub+"\n");
-
+            fw.write(this.getReactionLine(r));
         }
-
         fw.close();
 
     }
+
+
+    /**
+     * Get reaction information in a String
+     * @param r a {@link BioReaction}
+     * @return a String
+     */
+    protected String getReactionLine(BioReaction r) {
+        String name = r.getName();
+        String formulaIds = BioReactionUtils.getEquation(r, false, revSep, irrevSep, true);
+        String formulaNames =BioReactionUtils.getEquation(r, true, revSep, irrevSep, true);
+        String ec = r.getEcNumber() == null ? "NA" : r.getEcNumber();
+        String pathways = BioReactionUtils.getPathwaysString(r, this.network,true, " ; ");
+        String gpr = BioReactionUtils.getGPR(this.network, r);
+        Flux lowerBound = ReactionAttributes.getLowerBound(r);
+        String lb = lowerBound != null ? lowerBound.value.toString() : "NA";
+        Flux upperBound = ReactionAttributes.getUpperBound(r);
+        String ub = upperBound != null ? upperBound.value.toString() : "NA";
+
+        return r.getId()+"\t"+name+"\t"+formulaIds+"\t"+formulaNames+"\t"+ec+"\t"
+                + pathways + "\t" + gpr + "\t" + lb + "\t" +ub+"\n";
+    }
+
 }
diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/Tab2BioNetwork.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/Tab2BioNetwork.java
index 3bcaa4bd97b7be085bd8d6245a18b846e3fe52eb..63622ba555fa64101a1e00123acd44ec2f8d187b 100644
--- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/Tab2BioNetwork.java
+++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/Tab2BioNetwork.java
@@ -54,6 +54,8 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils.isDouble;
+
 
 /**
  * <p>Tab2BioNetwork class.</p>
@@ -77,22 +79,26 @@ public class Tab2BioNetwork {
     private BioNetwork bioNetwork;
 
     private BioCompartment defaultCompartment;
+    private HashSet<String> reactions;
+
+    // To transform metabolite id like this cpd[c] in cpd_c
+    private Pattern cpdWithBracketsPattern = Pattern.compile("^.*(\\[([^\\]]*)\\])$");
 
 
     /**
      * <p>Constructor for Tab2BioNetwork.</p>
      *
-     * @param networkId a {@link java.lang.String} object.
-     * @param colId a int.
-     * @param colFormula a int.
-     * @param formatReactionCobra a {@link java.lang.Boolean} object.
-     * @param formatMetaboliteCobra a {@link java.lang.Boolean} object.
-     * @param flagExternal a {@link java.lang.String} object.
-     * @param irrReaction a {@link java.lang.String} object.
-     * @param revReaction a {@link java.lang.String} object.
+     * @param networkId                          a {@link java.lang.String} object.
+     * @param colId                              a int.
+     * @param colFormula                         a int.
+     * @param formatReactionCobra                a {@link java.lang.Boolean} object.
+     * @param formatMetaboliteCobra              a {@link java.lang.Boolean} object.
+     * @param flagExternal                       a {@link java.lang.String} object.
+     * @param irrReaction                        a {@link java.lang.String} object.
+     * @param revReaction                        a {@link java.lang.String} object.
      * @param addCompartmentFromMetaboliteSuffix a {@link java.lang.Boolean} object.
-     * @param defaultCompartment a {@link java.lang.String} object.
-     * @param nSkip a int.
+     * @param defaultCompartment                 a {@link java.lang.String} object.
+     * @param nSkip                              a int.
      */
     public Tab2BioNetwork(String networkId, int colId, int colFormula, Boolean formatReactionCobra, Boolean formatMetaboliteCobra,
                           String flagExternal, String irrReaction, String revReaction,
@@ -113,6 +119,8 @@ public class Tab2BioNetwork {
 
         this.defaultCompartment = new BioCompartment(this.defaultCompartmentId, this.defaultCompartmentId);
 
+        reactions = new HashSet<>();
+
     }
 
     /**
@@ -137,383 +145,326 @@ public class Tab2BioNetwork {
             return false;
         }
 
-        String ligne;
+        String line;
 
         int nLines = 0;
 
-        Set<String> reactions = new HashSet<String>();
-
-        while ((ligne = br.readLine()) != null) {
+        reactions.clear();
 
+        while ((line = br.readLine()) != null) {
             nLines++;
 
-            if (nLines > this.nSkip && !ligne.startsWith("#")) {
+            Boolean flagLine = this.testLine(line, nLines);
 
-                String[] tab = ligne.split("\\t");
-
-                if (tab.length < this.colId || tab.length < this.colFormula) {
-                    System.err.println("Bad number of columns line " + nLines);
-                    flag = false;
-                } else {
-                    String id = tab[this.colId];
-                    String formula = tab[this.colFormula];
+            if (!flagLine) {
+                flag = false;
+            }
+        }
 
-                    // remove spaces
-                    id = id.trim();
-                    if (id.equals("")) {
-                        System.err.println("Reaction id empty line " + nLines);
-                        flag = false;
-                    }
+        if (flag == false) {
+            System.err.println("Input file badly formatted");
+        } else {
+            System.err.println("The input file looks good and contains " + reactions.size() + " reactions");
+        }
 
-                    if (reactions.contains(id)) {
-                        System.err.println("Duplicated reaction id : " + id + " line " + nLines);
-                        flag = false;
-                    } else {
-                        reactions.add(id);
-                    }
+        in.close();
 
-                    if (!formula.contains(this.irrReaction) && !formula.contains(this.revReaction)) {
-                        System.err.println("Reaction formula badly formatted line " + nLines + " : " + formula);
-                        flag = false;
-                    }
+        return flag;
+    }
 
-                    // in some palsson files, the compartment is specified at the beginning of the formula :
-                    // [c] : g3p + nad + pi <==> 13dpg + h + nadh
-                    Pattern compartment_Pattern = Pattern.compile("^(\\[.*\\] : ).*$");
-                    Matcher matcher = compartment_Pattern.matcher(formula);
 
-                    if (matcher.matches()) {
-                        String occurence = matcher.group(1);
+    /**
+     * Check if the line is correct
+     *
+     * @param line
+     * @param nLines
+     * @return
+     */
+    protected Boolean testLine(String line, int nLines) {
 
-                        formula = formula.replace(occurence, "");
-                    }
+        Boolean flag = true;
 
-                    String[] tabFormula;
-                    if (formula.contains(this.revReaction)) {
-                        tabFormula = formula.split(this.revReaction);
-                    } else {
-                        tabFormula = formula.split(this.irrReaction);
-                    }
+        if (nLines > this.nSkip && !line.startsWith("#")) {
 
-                    String leftString = tabFormula[0].trim();
+            String[] tab = line.split("\\t");
 
-                    String[] lefts = {};
+            Pattern pattern = Pattern.compile("\\t");
+            Matcher matcherTabulation = pattern.matcher(line);
+            long nbColumns = matcherTabulation.results().count() + 1;
 
-                    if (!leftString.equals("")) {
-                        lefts = leftString.split(" \\+ ");
-                    }
+            if (nbColumns <= this.colId || nbColumns <= this.colFormula) {
+                System.err.println("Bad number of columns line " + nLines);
+                flag = false;
+            } else {
+                String id = tab[this.colId];
+                String formula = tab[this.colFormula];
 
-                    String rightString;
+                // remove spaces
+                id = id.trim();
+                if (id.equals("")) {
+                    System.err.println("Reaction id empty line " + nLines);
+                    flag = false;
+                }
 
-                    if (tabFormula.length == 2) {
-                        rightString = tabFormula[1].trim();
-                    } else {
-                        rightString = "";
-                    }
+                if (reactions.contains(id)) {
+                    System.err.println("Duplicated reaction id : " + id + " line " + nLines);
+                    flag = false;
+                } else {
+                    reactions.add(id);
+                }
 
+                if (!formula.contains(this.irrReaction) && !formula.contains(this.revReaction)) {
+                    System.err.println("Reaction formula badly formatted line " + nLines + " : " + formula);
+                    flag = false;
+                }
 
-                    String[] rights = {};
-                    if (!rightString.equals("")) {
-                        rights = rightString.split(" \\+ ");
-                    }
+                // in some palsson files, the compartment is specified at the beginning of the formula :
+                // [c] : g3p + nad + pi <==> 13dpg + h + nadh
+                Pattern compartment_Pattern = Pattern.compile("^(\\[.+\\]\\s*:\\s*).*$");
+                Matcher matcher = compartment_Pattern.matcher(formula);
 
-                    for (String cpdId : lefts) {
+                if (matcher.matches()) {
+                    String occurence = matcher.group(1);
 
-                        cpdId = cpdId.trim();
+                    formula = formula.replace(occurence, "");
+                }
 
-                        String sto = "1";
+                String[] tabFormula;
+                if (formula.contains(this.revReaction)) {
+                    tabFormula = formula.split(this.revReaction);
+                } else {
+                    tabFormula = formula.split(this.irrReaction);
+                }
 
-                        String[] t = cpdId.split(" ");
+                String leftString = tabFormula[0].trim();
 
-                        if (t.length > 2) {
-                            System.err.println("Some extra spaces present in metabolite " + cpdId + " line " + nLines + " : " + formula);
-                            flag = false;
-                        }
+                String[] lefts = {};
 
-                        if (t.length == 2) {
-                            sto = t[0];
-                            sto = sto.replace("(", "").replace(")", "").trim();
-                            cpdId = t[1].trim();
-                        }
+                if (!leftString.equals("")) {
+                    lefts = leftString.split(" \\+ ");
+                }
 
+                String rightString;
 
-                    }
+                if (tabFormula.length == 2) {
+                    rightString = tabFormula[1].trim();
+                } else {
+                    rightString = "";
+                }
 
-                    for (String cpdId : rights) {
 
-                        cpdId = cpdId.trim();
+                String[] rights = {};
+                if (!rightString.equals("")) {
+                    rights = rightString.split(" \\+ ");
+                }
 
-                        String sto = "1";
+                for (String cpdId : lefts) {
 
-                        String[] t = cpdId.split(" ");
+                    cpdId = cpdId.trim();
 
-                        if (t.length > 2) {
-                            System.err.println("Some extra spaces present in metabolite " + cpdId + " line " + nLines + " : " + formula);
-                        }
+                    String[] t = cpdId.split(" ");
 
-                        if (t.length == 2) {
-                            sto = t[0];
-                            sto = sto.replace("(", "").replace(")", "").trim();
-                            cpdId = t[1].trim();
-                        }
+                    if (t.length > 2) {
+                        System.err.println("Some extra spaces present in metabolite " + cpdId + " line " + nLines + " : " + formula);
+                        flag = false;
                     }
-
                 }
-            }
-        }
 
-        if (flag == false) {
-            System.err.println("Input file badly formatted");
-        } else {
-            System.err.println("The input file looks good and contains " + reactions.size() + " reactions");
-        }
+                for (String cpdId : rights) {
 
-        in.close();
+                    cpdId = cpdId.trim();
+
+                    String[] t = cpdId.split(" ");
 
+                    if (t.length > 2) {
+                        System.err.println("Some extra spaces present in metabolite " + cpdId + " line " + nLines + " : " + formula);
+                        flag = false;
+                    }
+                }
+            }
+        }
         return flag;
     }
 
-
     /**
-     * Fill the network from formulas in the file
+     * Parses a line and create entities
      *
-     * @param fileIn a {@link java.lang.String} object.
-     * @return a {@link java.lang.Boolean} object.
-     * @throws java.io.IOException if any.
+     * @param line
+     * @param nLines
+     * @return true if everything ok
      */
-    public Boolean createReactionsFromFile(String fileIn) throws IOException {
+    protected Boolean parseLine(String line, int nLines) {
 
         Boolean flag = true;
 
-        try {
-            flag = this.testFile(fileIn);
-        } catch (IOException e) {
-            return false;
-        }
-
-        if (!flag) {
-            return false;
-        }
-
-        FileInputStream in = new FileInputStream(fileIn);
-        InputStreamReader ipsr = new InputStreamReader(in);
-        BufferedReader br = new BufferedReader(ipsr);
-        String ligne;
+        if (nLines > this.nSkip && !line.startsWith("#")) {
 
-        int nLines = 0;
+            String[] tab = line.split("\\t");
 
-
-        if (!this.addCompartmentFromMetaboliteSuffix) {
-            this.bioNetwork.add(defaultCompartment);
-        }
-
-
-        while ((ligne = br.readLine()) != null) {
-
-            nLines++;
-
-            if (nLines > this.nSkip && !ligne.startsWith("#")) {
-
-                String[] tab = ligne.split("\\t");
-
-                String id = tab[this.colId].trim();
+            String id = tab[this.colId].trim();
 
 //				id = id.replaceAll("[^A-Za-z0-9_]", "_");
 
 //				id = StringUtils.sbmlEncode(id);
 
-                String formula = tab[this.colFormula];
+            String formula = tab[this.colFormula];
 
-                BioReaction reaction;
+            BioReaction reaction;
 
-                String reactionId = id;
-                if (this.formatReactionCobra) {
-                    reactionId = StringUtils.formatReactionIdCobra(id);
-                }
+            String reactionId = id;
+            if (this.formatReactionCobra) {
+                reactionId = StringUtils.formatReactionIdCobra(id);
+            }
 
-                reaction = new BioReaction(reactionId);
+            reaction = new BioReaction(reactionId);
 
-                this.bioNetwork.add(reaction);
+            this.bioNetwork.add(reaction);
 
-                // in some palsson files, the compartment is specified at the beginning of the formula :
-                // [c] : g3p + nad + pi <==> 13dpg + h + nadh
-                Pattern compartment_Pattern = Pattern.compile("^(\\[.*\\] : ).*$");
-                Matcher matcher = compartment_Pattern.matcher(formula);
+            // in some palsson files, the compartment is specified at the beginning of the formula :
+            // [c] : g3p + nad + pi <==> 13dpg + h + nadh
+            Pattern compartment_Pattern = Pattern.compile("^(\\[(.+)\\]\\s*:\\s*).*$");
+            Matcher matcher = compartment_Pattern.matcher(formula);
 
-                String compartmentId = "";
+            String compartmentId = "";
 
-                if (matcher.matches()) {
-                    String occurence = matcher.group(1);
+            if (matcher.matches()) {
+                String occurence = matcher.group(1);
 
-                    String[] tabOcc = occurence.split(":");
+                //String[] tabOcc = occurence.split(":");
 
-                    compartmentId = tabOcc[0].replace("[", "").replace("]", "").trim();
+                //compartmentId = tabOcc[0].replace("[", "").replace("]", "").trim();
+                compartmentId = matcher.group(2);
 
-                    formula = formula.replace(occurence, "");
-                }
+                formula = formula.replace(occurence, "");
+            }
 
 
-                String[] tabFormula;
-                if (formula.contains(this.revReaction)) {
-                    reaction.setReversible(true);
-                    tabFormula = formula.split(this.revReaction);
-                } else {
-                    reaction.setReversible(false);
-                    tabFormula = formula.split(this.irrReaction);
-                }
+            String[] tabFormula;
+            if (formula.contains(this.revReaction)) {
+                reaction.setReversible(true);
+                tabFormula = formula.split(this.revReaction);
+            } else {
+                reaction.setReversible(false);
+                tabFormula = formula.split(this.irrReaction);
+            }
 
-                String leftString = tabFormula[0].trim();
+            String leftString = tabFormula[0].trim();
 
 
-                List<String> lefts = new ArrayList<String>();
+            List<String> lefts = new ArrayList<>();
 
 
-                if (!leftString.equals("")) {
-                    lefts = Arrays.asList(leftString.split(" \\+"));
-                }
+            if (!leftString.equals("")) {
+                lefts = Arrays.asList(leftString.split(" \\+"));
+            }
 
-                String rightString;
+            String rightString = tabFormula[1].trim();
 
-                if (tabFormula.length == 2) {
-                    rightString = tabFormula[1].trim();
-                } else {
-                    rightString = "";
-                }
+            List<String> rights = new ArrayList<>();
 
-                List<String> rights = new ArrayList<String>();
-                if (!rightString.equals("")) {
-                    rights = Arrays.asList(rightString.split(" \\+ "));
-                }
+            if (!rightString.equals("")) {
+                rights = Arrays.asList(rightString.split(" \\+ "));
+            }
 
-                // To transform metabolite id like this cpd[c] in cpd_c
-                Pattern cpd_Pattern = Pattern.compile("^.*(\\[([^\\]]*)\\])$");
+            for (String cpdId : lefts) {
+                parseReactant(reaction, compartmentId, cpdId, false);
+            }
 
-                // To see if the id ends with _something
-//				Pattern cpt_Pattern = Pattern.compile("^.*_([^_])*$");
+            for (String cpdId : rights) {
+                parseReactant(reaction, compartmentId, cpdId, true);
+            }
 
-                // Flag to check if external metabolite ids have been created
-//				Boolean flagExt = true;
-//
-//				while (flagExt) {
-//					flagExt = false;
+        }
+        return flag;
+    }
 
-                for (String cpdId : lefts) {
+    /**
+     * Parse
+     * @param reaction
+     * @param compartmentId
+     * @param cpdId
+     * @param rightSide
+     */
+    private void parseReactant(BioReaction reaction, String compartmentId, String cpdId, Boolean rightSide) {
+        cpdId = cpdId.trim();
 
-                    cpdId = cpdId.trim();
+        String sto = "1";
 
-                    String sto = "1";
+        String[] t = cpdId.split(" ");
 
-                    String[] t = cpdId.split(" ");
+        if (t.length == 2) {
+            sto = t[0];
+            sto = sto.replace("(", "").replace(")", "").trim();
+            cpdId = t[1].trim();
+        }
 
-                    if (t.length == 2) {
-                        sto = t[0];
-                        sto = sto.replace("(", "").replace(")", "").trim();
-                        cpdId = t[1].trim();
-                    }
+        Matcher matcherCpd = cpdWithBracketsPattern.matcher(cpdId);
 
-                    Matcher matcherCpd = cpd_Pattern.matcher(cpdId);
+        boolean addCompartment = false;
 
-                    if (matcherCpd.matches()) {
-                        cpdId = cpdId.replace(matcherCpd.group(1), "_" + matcherCpd.group(2));
-                    } else {
-                        if (!compartmentId.equals("") && !leftString.equals("")) {
-                            cpdId = cpdId + "_" + compartmentId;
-                        }
-                    }
+        if (matcherCpd.matches()) {
+            cpdId = cpdId.replace(matcherCpd.group(1), "_" + matcherCpd.group(2));
+            addCompartment = true;
+        } else {
+            if (!compartmentId.equals("") ) {
+                addCompartment = true;
+                cpdId = cpdId + "_" + compartmentId;
+            }
+        }
 
-                    Double stoDouble = 1.0;
-                    if(fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils.isDouble(sto)) {
-                        stoDouble = Double.parseDouble(sto);
-                    }
+        Double stoDouble = 1.0;
+        if (isDouble(sto)) {
+            stoDouble = Double.parseDouble(sto);
+        }
 
-//						cpdId = cpdId.replaceAll("[^A-Za-z0-9_]", "_");
-
-                    BioReactant reactant = this.initReactant(cpdId, stoDouble);
-
-                    this.bioNetwork.affectLeft(reaction, reactant);
-
-                    // We create the corresponding external metabolite
-//						if(rightString.equals("")) {
-//							String cpdExternalId = cpdId+this.flagExternal;
-//
-//							Matcher matcherCpt = cpt_Pattern.matcher(cpdId);
-//
-//							// If the metabolite contains compartment id in its suffix, we replace
-//							// it in the external metabolite id by the external suffix
-//
-//							if(matcherCpt.matches()) {
-//								String cptId = matcherCpt.group(1);
-//								if(this.getBioNetwork().getCompartments().containsKey(cptId)) {
-//									cpdExternalId = cpdId.replace("_"+cptId, this.flagExternal);
-//								}
-//							}
-//
-//							rights.add(cpdExternalId);
-//						}
-                }
+        this.initReactant(reaction, cpdId, stoDouble, rightSide, addCompartment);
+    }
 
-                for (String cpdId : rights) {
 
-                    cpdId = cpdId.trim();
+    /**
+     * Fill the network from formulas in the file
+     *
+     * @param fileIn a {@link java.lang.String} object.
+     * @return a {@link java.lang.Boolean} object.
+     * @throws java.io.IOException if any.
+     */
+    public Boolean createReactionsFromFile(String fileIn) throws IOException {
 
-                    String sto = "1";
+        Boolean flag;
 
-                    String[] t = cpdId.split(" ");
+        try {
+            flag = this.testFile(fileIn);
+        } catch (IOException e) {
+            return false;
+        }
 
-                    if (t.length == 2) {
-                        sto = t[0];
-                        sto = sto.replace("(", "").replace(")", "").trim();
-                        cpdId = t[1].trim();
-                    }
+        if (!flag) {
+            return false;
+        }
 
-                    Matcher matcherCpd = cpd_Pattern.matcher(cpdId);
+        FileInputStream in = new FileInputStream(fileIn);
+        InputStreamReader ipsr = new InputStreamReader(in);
+        BufferedReader br = new BufferedReader(ipsr);
+        String line;
 
-                    if (matcherCpd.matches()) {
-                        cpdId = cpdId.replace(matcherCpd.group(1), "_" + matcherCpd.group(2));
-                    } else {
-                        if (!compartmentId.equals("") && !rightString.equals("")) {
-                            cpdId = cpdId + "_" + compartmentId;
-                        }
-                    }
+        int nLines = 0;
 
 
-//						cpdId = cpdId.replaceAll("[^A-Za-z0-9_]", "_");
+        if (!this.addCompartmentFromMetaboliteSuffix) {
+            this.bioNetwork.add(defaultCompartment);
+        }
 
-                    Double stoDouble = 1.0;
-                    if(fr.inrae.toulouse.metexplore.met4j_core.utils.StringUtils.isDouble(sto)) {
-                        stoDouble = Double.parseDouble(sto);
-                    }
+        reactions.clear();
 
-//						cpdId = cpdId.replaceAll("[^A-Za-z0-9_]", "_");
-
-                    BioReactant reactant = this.initReactant(cpdId, stoDouble);
-
-                    this.bioNetwork.affectRight(reaction, reactant);
-
-                    // We create the corresponding external metabolite
-//						if(leftString.equals("")) {
-//							String cpdExternalId = cpdId+this.flagExternal;
-//
-//							Matcher matcherCpt = cpt_Pattern.matcher(cpdId);
-//
-//							// If the metabolite contains compartment id in its suffix, we replace
-//							// it in the external metabolite id by the external suffix
-//
-//							if(matcherCpt.matches()) {
-//								String cptId = matcherCpt.group(1);
-//								if(this.getBioNetwork().getCompartments().containsKey(cptId)) {
-//									cpdExternalId = cpdId.replace("_"+cptId, this.flagExternal);
-//								}
-//							}
-//
-//							lefts.add(cpdExternalId);
-//							flagExt=true;
-//						}
-//					}
-                }
+        while ((line = br.readLine()) != null) {
 
-            }
+            nLines++;
 
+            Boolean flagLine = this.parseLine(line, nLines);
+
+            if (!flagLine) {
+                flag = false;
+            }
         }
 
         br.close();
@@ -530,11 +481,11 @@ public class Tab2BioNetwork {
      * @param cpdId
      * @return
      */
-    private BioReactant initReactant(String cpdId, Double coeff) {
+    private void initReactant(BioReaction reaction, String cpdId, Double coeff, Boolean rightSide, Boolean addCompartment) {
 
         BioCompartment compartment = defaultCompartment;
 
-        if (this.addCompartmentFromMetaboliteSuffix) {
+        if (this.addCompartmentFromMetaboliteSuffix || addCompartment) {
             String[] t = cpdId.split("_");
 
             String compartmentId = this.defaultCompartment.getId();
@@ -552,32 +503,41 @@ public class Tab2BioNetwork {
                 this.bioNetwork.add(compartment);
             }
         }
-
-
-            if (this.formatMetaboliteCobra) {
-                cpdId = StringUtils.formatMetaboliteIdCobra(cpdId, compartment.getId());
+        else {
+            if(! this.bioNetwork.contains(compartment)) {
+                this.bioNetwork.add(compartment);
             }
+        }
 
-            BioMetabolite cpd;
-            BioCollection<BioMetabolite> metabolitesView = this.bioNetwork.getMetabolitesView();
 
-            if (metabolitesView.containsId(cpdId)) {
-                cpd = metabolitesView.get(cpdId);
-            } else {
-                cpd = new BioMetabolite(cpdId);
-                this.bioNetwork.add(cpd);
-            }
-            this.bioNetwork.affectToCompartment(compartment, cpd);
+        if (this.formatMetaboliteCobra) {
+            cpdId = StringUtils.formatMetaboliteIdCobra(cpdId, compartment.getId());
+        }
 
-            if (cpd.getId().endsWith(this.flagExternal)) {
-                MetaboliteAttributes.setBoundaryCondition(cpd, true);
-            } else {
-                MetaboliteAttributes.setBoundaryCondition(cpd, false);
-            }
+        BioMetabolite cpd;
+        BioCollection<BioMetabolite> metabolitesView = this.bioNetwork.getMetabolitesView();
 
+        if (metabolitesView.containsId(cpdId)) {
+            cpd = metabolitesView.get(cpdId);
+        } else {
+            cpd = new BioMetabolite(cpdId);
+            this.bioNetwork.add(cpd);
+        }
+        this.bioNetwork.affectToCompartment(compartment, cpd);
+
+        if (cpd.getId().endsWith(this.flagExternal)) {
+            MetaboliteAttributes.setBoundaryCondition(cpd, true);
+        } else {
+            MetaboliteAttributes.setBoundaryCondition(cpd, false);
+        }
 
+        if (!rightSide) {
+            this.bioNetwork.affectLeft(reaction, coeff, compartment, cpd);
+        } else {
+            this.bioNetwork.affectRight(reaction, coeff, compartment, cpd);
+        }
 
-        return new BioReactant(cpd, coeff, compartment );
+        return;
 
     }
 
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/reactant/ReactantAttributesTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/gpr/GPRTest.java
similarity index 58%
rename from met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/reactant/ReactantAttributesTest.java
rename to met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/gpr/GPRTest.java
index 9870a1cddd9328990295f42eed63946e1e8d7551..fdd871409aa0ed20f4e69cf0ece25fa5682d42c3 100644
--- a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/reactant/ReactantAttributesTest.java
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/annotations/gpr/GPRTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright INRAE (2020)
+ * Copyright INRAE (2022)
  *
  * contact-metexplore@inrae.fr
  *
@@ -34,56 +34,42 @@
  *
  */
 
-package fr.inrae.toulouse.metexplore.met4j_io.annotations.reactant;
+package fr.inrae.toulouse.metexplore.met4j_io.annotations.gpr;
 
-import static org.junit.Assert.*;
-
-import org.junit.Before;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.errors.MalformedGeneAssociationStringException;
 import org.junit.Test;
 
-import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment;
-import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
-import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant;
-import fr.inrae.toulouse.metexplore.met4j_io.annotations.GenericAttributes;
-
-public class ReactantAttributesTest {
-
-	BioReactant r;
-	BioCompartment c;
-	BioMetabolite m;
-
-	@Before
-	public void init() {
-		m = new BioMetabolite("m");
-		c = new BioCompartment("c");
-
-		r = new BioReactant(m, 1.0, c);
-	}
-
-	@Test
-	public void testGetConstant() {
-
-		assertFalse(ReactantAttributes.getConstant(r));
+import static org.junit.Assert.*;
 
-		r.setAttribute(GenericAttributes.CONSTANT, false);
+public class GPRTest {
 
-		assertFalse(ReactantAttributes.getConstant(r));
+    @Test
+    public void createGPRfromString() throws MalformedGeneAssociationStringException {
 
-		r.setAttribute(GenericAttributes.CONSTANT, true);
+        BioNetwork network = new BioNetwork();
+        BioEnzyme e1 = new BioEnzyme("e1");
+        BioEnzyme e2 = new BioEnzyme("e2");
+        BioProtein p1 = new BioProtein("p1");
+        BioProtein p2 = new BioProtein("p2");
+        BioGene g1 = new BioGene("g1");
+        BioGene g2 = new BioGene("g2");
+        BioReaction r1 = new BioReaction("r1");
 
-		assertTrue(ReactantAttributes.getConstant(r));
+        network.add(e1, e2, p1, p2, g1, g2, r1);
 
-	}
+        network.affectGeneProduct(p1, g1);
+        network.affectSubUnit(e1, 1.0, p1);
+        network.affectEnzyme(r1, e1);
 
-	@Test
-	public void testSetConstant() {
+        GPR.createGPRfromString(network, r1, "G3 AND G4");
 
-		ReactantAttributes.setConstant(r, false);
-		assertFalse((Boolean) r.getAttribute(GenericAttributes.CONSTANT));
+        assertEquals(1, r1.getEnzymesView().size());
 
-		ReactantAttributes.setConstant(r, true);
-		assertTrue((Boolean) r.getAttribute(GenericAttributes.CONSTANT));
+        assertEquals(2, network.getGenesFromReactions(r1).size());
 
-	}
+        assertTrue(network.getGenesFromReactions(r1).containsId("G3"));
+        assertTrue(network.getGenesFromReactions(r1).containsId("G4"));
 
-}
+    }
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetworkTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetworkTest.java
index af0bd86c0c85ff3607896bc29da01b4c55a329a7..a40074b221fb6fecaef309a7d98446923509fb9c 100644
--- a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetworkTest.java
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/jsbml/reader/JsbmlToBioNetworkTest.java
@@ -78,7 +78,6 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.compartment.BioCompartmentType;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.compartment.CompartmentAttributes;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.network.NetworkAttributes;
-import fr.inrae.toulouse.metexplore.met4j_io.annotations.reactant.ReactantAttributes;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.reaction.Flux;
 import fr.inrae.toulouse.metexplore.met4j_io.jsbml.attributes.Notes;
 import fr.inrae.toulouse.metexplore.met4j_io.jsbml.attributes.SbmlAnnotation;
@@ -521,22 +520,16 @@ public class JsbmlToBioNetworkTest {
 
 		assertNotNull(m1Ref);
 
-		assertTrue(ReactantAttributes.getConstant(m1Ref));
-
 		BioReactant m2Ref = parser.getNetwork().getRightReactants(reaction1).stream()
 				.filter((x) -> x.getPhysicalEntity().getId().compareTo("m2") == 0).findFirst().orElse(null);
 
 		assertNotNull(m2Ref);
 
-		assertFalse(ReactantAttributes.getConstant(m2Ref));
-
 		BioReactant m1RefBis = parser.getNetwork().getRightReactants(reaction1).stream()
 				.filter((x) -> x.getPhysicalEntity().getId().compareTo("m1") == 0).findFirst().orElse(null);
 
 		assertNotNull(m1RefBis);
 
-		assertFalse(ReactantAttributes.getConstant(m1RefBis));
-
 		// Test sbo term
 		String sboTerm = ReactionAttributes.getSboTerm(reaction1);
 
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFileTest.java
index 970e31d3ac0fe12320ee95c1155b83c46ddcc3d8..d04b90e7759dc4cc0053557637d057eba0b4abde 100644
--- a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFileTest.java
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetBoundsFromFileTest.java
@@ -40,7 +40,6 @@ import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
 import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.reaction.Flux;
 import fr.inrae.toulouse.metexplore.met4j_io.annotations.reaction.ReactionAttributes;
-import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.mockito.Mockito;
@@ -207,7 +206,7 @@ public class SetBoundsFromFileTest {
     public void setLowerBounds() throws IOException {
         SetBoundsFromFile c = Mockito.spy(new SetBoundsFromFile(0, 1, network, "", "#", 1, false, BoundsType.LOWER));
 
-        Mockito.doReturn(true).when(c).test();
+        Mockito.doReturn(true).when(c).parseAttributeFile();
 
         String line = "r1\t12.0\n";
 
@@ -229,7 +228,7 @@ public class SetBoundsFromFileTest {
     public void setUpperBounds() throws IOException {
         SetBoundsFromFile c = Mockito.spy(new SetBoundsFromFile(0, 1, network, "", "#", 1, false, BoundsType.UPPER));
 
-        Mockito.doReturn(true).when(c).test();
+        Mockito.doReturn(true).when(c).parseAttributeFile();
 
         String line = "r1\t12.0\n";
 
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetChargesFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetChargesFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..44283bda12234a0844b0f095528ad4aec06b49ed
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetChargesFromFileTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class SetChargesFromFileTest {
+
+
+    private static BioNetwork network;
+    private static BioMetabolite m;
+    private static BioMetabolite m_cpd_c;
+
+
+    @BeforeClass
+    public static void init() {
+        network = new BioNetwork();
+        m = new BioMetabolite("m");
+        BioMetabolite m_cpd = new BioMetabolite("M_cpd");
+        BioMetabolite cpd_c = new BioMetabolite("cpd_c");
+        m_cpd_c = new BioMetabolite("M_cpd_c");
+
+        BioCompartment c = new BioCompartment("c");
+        network.add(m, m_cpd, cpd_c, c, m_cpd_c);
+
+        network.affectToCompartment(c, cpd_c, m_cpd_c);
+
+    }
+
+    @Test
+    public void testAttribute() {
+        SetChargesFromFile app = new SetChargesFromFile(1, 2, network, "", "#", 1, false, false);
+
+        assertTrue(app.testAttribute("2"));
+        assertTrue(app.testAttribute("2.0"));
+        assertFalse(app.testAttribute("NA"));
+    }
+
+
+    @Test
+    public void testParseLine() {
+        SetChargesFromFile app = new SetChargesFromFile(0, 1, network, "", "#", 0, false, false);
+        String line = "m\t2\n";
+
+        Boolean flag = app.parseLine(line, 1);
+        assertTrue(flag);
+
+        assertTrue(app.getIdAttributeMap().containsKey("m"));
+
+        line = "something\t2\n";
+
+        flag = app.parseLine(line, 1);
+        assertTrue(flag);
+
+        // A line with an absent metabolite is accepted but not registered in the map
+        assertFalse(app.getIdAttributeMap().containsKey("something"));
+
+    }
+
+    @Test
+    public void testParseLinePrefixMetabolite() {
+
+        SetChargesFromFile app = new SetChargesFromFile(0, 1, network, "", "#", 0, true, false);
+
+        String line = "cpd\t2\n";
+
+        Boolean flag = app.parseLine(line, 1);
+        assertTrue(flag);
+
+        assertTrue(app.getIdAttributeMap().containsKey("M_cpd"));
+
+    }
+
+    @Test
+    public void testParseLineSuffixMetabolite() {
+
+        SetChargesFromFile app = new SetChargesFromFile(0, 1, network, "", "#", 0, false, true);
+
+        String line = "cpd\t2\n";
+
+        Boolean flag = app.parseLine(line, 1);
+        assertTrue(flag);
+
+        assertTrue(app.getIdAttributeMap().containsKey("cpd_c"));
+
+    }
+
+    @Test
+    public void testParseLineCompartmentBracketsMetabolite() {
+
+        SetChargesFromFile app = new SetChargesFromFile(0, 1, network, "", "#", 0, false, false);
+
+        String line = "cpd[c]\t2\n";
+
+        Boolean flag = app.parseLine(line, 1);
+        assertTrue(flag);
+
+        assertTrue(app.getIdAttributeMap().containsKey("cpd_c"));
+
+        app = new SetChargesFromFile(0, 1, network, "", "#", 0, false, true);
+
+        flag = app.parseLine(line, 1);
+        assertTrue(flag);
+
+        assertFalse(app.getIdAttributeMap().containsKey("cpd_c"));
+    }
+
+
+    @Test
+    public void testParseLineSuffixPrefix() {
+
+        SetChargesFromFile app = new SetChargesFromFile(0, 1, network, "", "#", 0, true, true);
+
+        String line = "cpd\t2\n";
+
+        Boolean flag = app.parseLine(line, 1);
+        assertTrue(flag);
+
+        assertTrue(app.getIdAttributeMap().containsKey("M_cpd_c"));
+
+        flag = app.parseLine(line, 1);
+        assertFalse(flag);
+
+    }
+
+    @Test
+    public void setAttributes() throws IOException {
+
+        SetChargesFromFile app = Mockito.spy(new SetChargesFromFile(0, 1, network, "", "#", 0, true, true));
+
+        Mockito.doReturn(true).when(app).parseAttributeFile();
+        String line = "cpd\t2\n";
+
+        app.parseLine(line, 1);
+
+        Boolean flag = app.setAttributes();
+
+        assertTrue(flag);
+
+        assertEquals(2, m_cpd_c.getCharge(), 0.0);
+
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void constructorBadColumnId() throws IOException {
+        SetChargesFromFile app = Mockito.spy(new SetChargesFromFile(-1, 1, network, "", "#", 0, true, true));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void constructorBadColumnAttribute() throws IOException {
+        SetChargesFromFile app = Mockito.spy(new SetChargesFromFile(1, -1, network, "", "#", 0, true, true));
+    }
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetEcsFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetEcsFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba0a9b1c01e7e862b24fe2af5d034a06e5aa80de
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetEcsFromFileTest.java
@@ -0,0 +1,144 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class SetEcsFromFileTest {
+
+
+    private SetEcsFromFile setEcsFromFile;
+    private BioNetwork network;
+    private BioReaction r;
+    private String line;
+
+    @Before
+    public void init() throws IOException {
+
+        network = new BioNetwork();
+        r = new BioReaction("r");
+        network.add(r);
+
+        line = "r\t1.2.3.5\n";
+
+        setEcsFromFile = Mockito.spy(new SetEcsFromFile(0, 1, network, "", "", 0, false, false));
+
+        Mockito.doReturn(true).when(setEcsFromFile).parseAttributeFile();
+
+
+    }
+
+    @Test
+    public void testAttributeNormal() {
+        String ec = "1.2.3.4";
+        assertTrue(setEcsFromFile.testAttribute(ec));
+        ec = "1.2.3.134";
+        assertTrue(setEcsFromFile.testAttribute(ec));
+        ec = "1.2.3.-";
+        assertTrue(setEcsFromFile.testAttribute(ec));
+        ec = "1.2.3";
+        assertTrue(setEcsFromFile.testAttribute(ec));
+        ec = "EC1.2.3.134";
+        assertTrue(setEcsFromFile.testAttribute(ec));
+        ec = "EC 1.2.3.134";
+        assertTrue(setEcsFromFile.testAttribute(ec));
+
+        ec = "1.2.3.4;1.4.32";
+        assertTrue(setEcsFromFile.testAttribute(ec));
+
+
+    }
+
+    @Test
+    public void testAttributeEmpty() {
+        String ec = "";
+
+        assertTrue(setEcsFromFile.testAttribute(ec));
+    }
+
+    @Test
+    public void testAttributeBadlyFormated() {
+        String ec = "NA";
+
+        assertFalse(setEcsFromFile.testAttribute(ec));
+
+        ec = "1.2.3.4|1.4.32";
+        assertFalse(setEcsFromFile.testAttribute(ec));
+
+        ec = "1.2.3.4;NA";
+        assertFalse(setEcsFromFile.testAttribute(ec));
+
+        ec = "1.2.3.4;";
+        assertFalse(setEcsFromFile.testAttribute(ec));
+    }
+
+    @Test
+    public void setAttributes() throws IOException {
+
+        Boolean flag = setEcsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setEcsFromFile.setAttributes();
+
+        assertEquals("1.2.3.5", r.getEcNumber());
+
+
+    }
+
+    @Test
+    public void setAttributeEmpty() throws IOException {
+        line = "r\t\ttruc\n";
+
+        Boolean flag = setEcsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setEcsFromFile.setAttributes();
+
+        assertEquals(null, r.getEcNumber());
+
+    }
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetFormulasFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetFormulasFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b08d4ce310b537245369195f6d96b7db29f06397
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetFormulasFromFileTest.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class SetFormulasFromFileTest {
+
+    private BioNetwork network;
+    private BioMetabolite metabolite;
+    private SetFormulasFromFile setFormulasFromFile;
+    private String line;
+
+    @Before
+    public void init() throws IOException {
+
+        network = new BioNetwork();
+        metabolite = new BioMetabolite("m");
+        network.add(metabolite);
+
+        setFormulasFromFile = Mockito.spy(new SetFormulasFromFile(0, 1, network, "", "#", 0, false, false));
+
+        Mockito.doReturn(true).when(setFormulasFromFile).parseAttributeFile();
+
+
+        line = "m\tCH3";
+    }
+
+
+    @Test
+    public void testAttribute() {
+
+        String s = "C2H3O6";
+
+        assertTrue(setFormulasFromFile.testAttribute(s));
+
+        s = "CH3O6";
+
+        assertTrue(setFormulasFromFile.testAttribute(s));
+
+    }
+
+    @Test
+    public void testAttributeEmpty() {
+
+        String s = "";
+
+        assertTrue(setFormulasFromFile.testAttribute(s));
+
+    }
+
+    @Test
+    public void testAttributeBadlyFormatted() {
+
+        String s = "tr";
+
+        assertFalse(setFormulasFromFile.testAttribute(s));
+
+    }
+
+    @Test
+    public void setAttributes() throws IOException {
+
+        Boolean flag = setFormulasFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setFormulasFromFile.setAttributes();
+
+        assertEquals("CH3", metabolite.getChemicalFormula());
+
+    }
+
+    @Test
+    public void setEmptyAttribute() throws IOException {
+
+        String line = "m\t\n";
+
+        Boolean flag = setFormulasFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setFormulasFromFile.setAttributes();
+
+        assertEquals(null, metabolite.getChemicalFormula());
+
+    }
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetGprsFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetGprsFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d502a5725a39b74e7e636814ff19aac8c62dd9a9
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetGprsFromFileTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+
+public class SetGprsFromFileTest {
+
+
+    private BioNetwork network;
+    private BioReaction reaction;
+    private SetGprsFromFile setGprsFromFile;
+
+    @Before
+    public void init() throws IOException {
+        network = new BioNetwork();
+        reaction = new BioReaction("r");
+        network.add(reaction);
+
+        setGprsFromFile = Mockito.spy(new SetGprsFromFile(0, 1, network, "", "", 0, false, false));
+
+        Mockito.doReturn(true).when(setGprsFromFile).parseAttributeFile();
+    }
+
+    @Test
+    public void testAttribute() {
+
+        assertTrue(setGprsFromFile.testAttribute("anything"));
+
+    }
+
+    @Test
+    public void setAttributes() throws IOException {
+
+        String line = "r\t(G1 and G2) or G3\n";
+
+        Boolean flag = setGprsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setGprsFromFile.setAttributes();
+
+        assertEquals(2, network.getEnzymesView().size());
+        assertEquals(3, network.getGenesView().size());
+        assertEquals(3, network.getProteinsView().size());
+        assertEquals(2, reaction.getEnzymesView().size());
+    }
+
+    @Test
+    public void setBadAttributes() throws IOException {
+
+        String line = "r\t(G1 and G2 or G3\n";
+
+        Boolean flag = setGprsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setGprsFromFile.setAttributes();
+
+        assertEquals(0, network.getEnzymesView().size());
+        assertEquals(0, network.getGenesView().size());
+        assertEquals(0, network.getProteinsView().size());
+        assertEquals(0, reaction.getEnzymesView().size());
+    }
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetNamesFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetNamesFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2dbb97acbc3dbd435e5781db99a42be00d4f6b34
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetNamesFromFileTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class SetNamesFromFileTest {
+
+    private BioNetwork network;
+    private BioReaction reaction;
+    private BioMetabolite metabolite;
+    private BioProtein protein;
+    private BioGene gene;
+    private BioPathway pathway;
+
+    @Before
+    public void init() {
+        network = new BioNetwork();
+        reaction = new BioReaction("r");
+        metabolite = new BioMetabolite("m");
+        protein = new BioProtein("p");
+        gene = new BioGene("g");
+        pathway = new BioPathway("pathway");
+
+        network.add(reaction, metabolite, protein, gene, pathway);
+
+
+    }
+
+
+    @Test
+    public void testAttribute() {
+        SetNamesFromFile setNamesFromFile = new SetNamesFromFile(0, 1, network, "", "", 0, false, false, EntityType.REACTION);
+
+        assertTrue(setNamesFromFile.testAttribute("anything"));
+    }
+
+    @Test
+    public void setAttributesReaction() throws IOException {
+
+        SetNamesFromFile setNamesFromFile = Mockito.spy(new SetNamesFromFile(0, 1, network, "", "", 0, false, false, EntityType.REACTION));
+        Mockito.doReturn(true).when(setNamesFromFile).parseAttributeFile();
+
+        String line = "r\tmyreaction\n";
+
+        Boolean flag = setNamesFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setNamesFromFile.setAttributes();
+
+        assertEquals("myreaction", reaction.getName());
+
+    }
+
+    @Test
+    public void setAttributesMetabolite() throws IOException {
+
+        SetNamesFromFile setNamesFromFile = Mockito.spy(new SetNamesFromFile(0, 1, network, "", "", 0, false, false, EntityType.METABOLITE));
+        Mockito.doReturn(true).when(setNamesFromFile).parseAttributeFile();
+
+        String line = "m\tmymetabolite\n";
+
+        Boolean flag = setNamesFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setNamesFromFile.setAttributes();
+
+        assertEquals("mymetabolite", metabolite.getName());
+
+    }
+
+    @Test
+    public void setAttributesProtein() throws IOException {
+
+        SetNamesFromFile setNamesFromFile = Mockito.spy(new SetNamesFromFile(0, 1, network, "", "", 0, false, false, EntityType.PROTEIN));
+        Mockito.doReturn(true).when(setNamesFromFile).parseAttributeFile();
+
+        String line = "p\tmyprotein\n";
+
+        Boolean flag = setNamesFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setNamesFromFile.setAttributes();
+
+        assertEquals("myprotein", protein.getName());
+
+    }
+
+    @Test
+    public void setAttributesGene() throws IOException {
+
+        SetNamesFromFile setNamesFromFile = Mockito.spy(new SetNamesFromFile(0, 1, network, "", "", 0, false, false, EntityType.GENE));
+        Mockito.doReturn(true).when(setNamesFromFile).parseAttributeFile();
+
+        String line = "g\tmygene\n";
+
+        Boolean flag = setNamesFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setNamesFromFile.setAttributes();
+
+        assertEquals("mygene", gene.getName());
+
+    }
+
+    @Test
+    public void setAttributesPathway() throws IOException {
+
+        SetNamesFromFile setNamesFromFile = Mockito.spy(new SetNamesFromFile(0, 1, network, "", "", 0, false, false, EntityType.PATHWAY));
+        Mockito.doReturn(true).when(setNamesFromFile).parseAttributeFile();
+
+        String line = "pathway\tmypathway\n";
+
+        Boolean flag = setNamesFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setNamesFromFile.setAttributes();
+
+        assertEquals("mypathway", pathway.getName());
+
+    }
+
+
+
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetPathwaysFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetPathwaysFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..8ded386a018a8ac8a725d46808ccdc5976e05b3d
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetPathwaysFromFileTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioPathway;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class SetPathwaysFromFileTest {
+
+
+    private BioNetwork network;
+    private BioReaction reaction;
+    private SetPathwaysFromFile setPathwaysFromFile;
+    private BioReaction reaction2;
+
+    @Before
+    public void init() throws IOException {
+        network = new BioNetwork();
+        reaction = new BioReaction("r");
+        reaction2 = new BioReaction("r2");
+
+        network.add(reaction, reaction2);
+        setPathwaysFromFile = Mockito.spy(new SetPathwaysFromFile(0, 1, network, "", "", 0, false, false, ";"));
+
+        Mockito.doReturn(true).when(setPathwaysFromFile).parseAttributeFile();
+
+    }
+
+    @Test
+    public void testAttribute() {
+
+        assertTrue(setPathwaysFromFile.testAttribute("anything"));
+
+    }
+
+    @Test
+    public void setAttributes() throws IOException {
+
+        String line = "r\tp1";
+
+        Boolean flag = setPathwaysFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setPathwaysFromFile.setAttributes();
+
+        assertEquals(1, network.getPathwaysView().size());
+        assertTrue(network.getPathwaysView().containsId("p1"));
+
+        BioPathway p = network.getPathwaysView().get("p1");
+
+        assertEquals(1, network.getReactionsFromPathways(p).size());
+        assertTrue(network.getReactionsFromPathways(p).containsId("r"));
+
+        line = "r2\tp1;p2";
+
+        flag = setPathwaysFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setPathwaysFromFile.setAttributes();
+
+        assertEquals(2, network.getPathwaysView().size());
+
+        assertTrue(network.getPathwaysView().containsId("p1"));
+        assertTrue(network.getPathwaysView().containsId("p2"));
+
+        assertEquals(2, network.getReactionsFromPathways(p).size());
+
+        BioPathway p2 = network.getPathwaysView().get("p2");
+
+        assertEquals(1, network.getReactionsFromPathways(p2).size());
+
+        assertTrue(network.getReactionsFromPathways(p).containsId("r2"));
+
+    }
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetRefsFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetRefsFromFileTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..179d33846749f1c583a0e125c805f5fba0e589ba
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetRefsFromFileTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.IOException;
+
+import static org.junit.Assert.*;
+
+public class SetRefsFromFileTest {
+
+
+    private BioNetwork network;
+    private BioReaction reaction;
+    private BioMetabolite metabolite;
+    private BioProtein protein;
+    private BioPathway pathway;
+    private BioGene gene;
+
+    @Before
+    public void init() {
+        network = new BioNetwork();
+        reaction = new BioReaction("r");
+        metabolite = new BioMetabolite("m");
+        protein = new BioProtein("p");
+        pathway = new BioPathway("pathway");
+        gene = new BioGene("g");
+
+        network.add(reaction, metabolite, protein, pathway, gene);
+    }
+    
+    @Test
+    public void testAttribute() {
+        SetRefsFromFile setRefsFromFile = new SetRefsFromFile(0, 1, network, "", "", 0, false, false, "refTest", EntityType.REACTION);
+        assertTrue(setRefsFromFile.testAttribute("anything"));
+    }
+
+    @Test
+    public void setAttributesReaction() throws IOException {
+        SetRefsFromFile setRefsFromFile = Mockito.spy(new SetRefsFromFile(0, 1, network, "", "", 0, false, false, "refTest", EntityType.REACTION));
+        Mockito.doReturn(true).when(setRefsFromFile).parseAttributeFile();
+
+        String line = "r\trefValue";
+        Boolean flag = setRefsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setRefsFromFile.setAttributes();
+        System.err.println(reaction.getRefs());
+        BioRef refRef = new BioRef("attributeTable", "refTest", "refValue", 1);
+
+        assertTrue(reaction.getRefs().get("refTest").contains(refRef));
+
+    }
+
+    @Test
+    public void setAttributesMetabolite() throws IOException {
+        SetRefsFromFile setRefsFromFile = Mockito.spy(new SetRefsFromFile(0, 1, network, "", "", 0, false, false, "refTest", EntityType.METABOLITE));
+        Mockito.doReturn(true).when(setRefsFromFile).parseAttributeFile();
+
+        String line = "m\trefValue";
+        Boolean flag = setRefsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setRefsFromFile.setAttributes();
+        assertTrue(metabolite.getRefs().containsKey("refTest"));
+        BioRef refRef = new BioRef("attributeTable", "refTest", "refValue", 1);
+        assertTrue(metabolite.getRefs().get("refTest").contains(refRef));
+    }
+
+    @Test
+    public void setAttributesGene() throws IOException {
+        SetRefsFromFile setRefsFromFile = Mockito.spy(new SetRefsFromFile(0, 1, network, "", "", 0, false, false, "refTest", EntityType.GENE));
+        Mockito.doReturn(true).when(setRefsFromFile).parseAttributeFile();
+
+        String line = "g\trefValue";
+        Boolean flag = setRefsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setRefsFromFile.setAttributes();
+        assertTrue(gene.getRefs().containsKey("refTest"));
+        BioRef refRef = new BioRef("attributeTable", "refTest", "refValue", 1);
+        assertTrue(gene.getRefs().get("refTest").contains(refRef));
+    }
+
+    @Test
+    public void setAttributesProtein() throws IOException {
+        SetRefsFromFile setRefsFromFile = Mockito.spy(new SetRefsFromFile(0, 1, network, "", "", 0, false, false, "refTest", EntityType.PROTEIN));
+        Mockito.doReturn(true).when(setRefsFromFile).parseAttributeFile();
+
+        String line = "p\trefValue";
+        Boolean flag = setRefsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setRefsFromFile.setAttributes();
+        System.err.println(protein.getRefs());
+        assertTrue(protein.getRefs().containsKey("refTest"));
+        BioRef refRef = new BioRef("attributeTable", "refTest", "refValue", 1);
+        assertTrue(protein.getRefs().get("refTest").contains(refRef));
+    }
+
+    @Test
+    public void setAttributesPathway() throws IOException {
+        SetRefsFromFile setRefsFromFile = Mockito.spy(new SetRefsFromFile(0, 1, network, "", "", 0, false, false, "refTest", EntityType.PATHWAY));
+        Mockito.doReturn(true).when(setRefsFromFile).parseAttributeFile();
+
+        String line = "pathway\trefValue";
+        Boolean flag = setRefsFromFile.parseLine(line, 1);
+
+        assertTrue(flag);
+
+        setRefsFromFile.setAttributes();
+        assertTrue(pathway.getRefs().containsKey("refTest"));
+        BioRef refRef = new BioRef("attributeTable", "refTest", "refValue", 1);
+        assertTrue(pathway.getRefs().get("refTest").contains(refRef));
+    }
+
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/BioNetwork2TabTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/BioNetwork2TabTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..2b44d575af6f5ef1aafaeea2220c615e69a8f30a
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/BioNetwork2TabTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.network;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
+import fr.inrae.toulouse.metexplore.met4j_io.annotations.reaction.Flux;
+import fr.inrae.toulouse.metexplore.met4j_io.annotations.reaction.ReactionAttributes;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class BioNetwork2TabTest {
+
+    @Test
+    public void getReactionLine() {
+
+        BioReaction r = new BioReaction("r", "reaction");
+        BioMetabolite m1 = new BioMetabolite("m1", "metabolite1");
+        BioMetabolite m2 = new BioMetabolite("m2", "metabolite2");
+        BioCompartment c = new BioCompartment("c");
+        BioGene g = new BioGene("g1");
+        BioProtein p = new BioProtein("p1");
+        BioEnzyme e = new BioEnzyme("e1");
+        BioPathway pathway1 = new BioPathway("p1");
+        BioPathway pathway2 = new BioPathway("p2");
+
+        BioNetwork network = new BioNetwork();
+        network.add(r, m1, m2, c, g, p, e, pathway1, pathway2);
+        network.affectToCompartment(c, m1, m2);
+        network.affectGeneProduct(p, g);
+        network.affectSubUnit(e, 1.0, p);
+        network.affectEnzyme(r, e);
+        network.affectLeft(r, 1.0, c, m1);
+        network.affectRight(r, 1.0, c, m2);
+        network.affectToPathway(pathway1, r);
+        network.affectToPathway(pathway2, r);
+
+        ReactionAttributes.setLowerBound(r, new Flux(-10.0));
+        ReactionAttributes.setUpperBound(r, new Flux(10.0));
+
+        BioNetwork2Tab app = new BioNetwork2Tab(network, "", "<-->", "-->");
+
+        String testLine = app.getReactionLine(r);
+        String refLine = "r\treaction\tm1[c] <--> m2[c]\tmetabolite1[c] <--> metabolite2[c]\tNA\tp1 ; p2\tg1\t-10.0\t10.0\n";
+
+        assertEquals(refLine, testLine);
+
+        r.setReversible(false);
+        testLine = app.getReactionLine(r);
+        refLine = "r\treaction\tm1[c] --> m2[c]\tmetabolite1[c] --> metabolite2[c]\tNA\tp1 ; p2\tg1\t-10.0\t10.0\n";
+
+        assertEquals(refLine, testLine);
+    }
+}
\ No newline at end of file
diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/Tab2BioNetworkTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/Tab2BioNetworkTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..97459633f336d9eee828b6c976f553ded0171237
--- /dev/null
+++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/network/Tab2BioNetworkTest.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright INRAE (2022)
+ *
+ * contact-metexplore@inrae.fr
+ *
+ * This software is a computer program whose purpose is to [describe
+ * functionalities and technical features of your software].
+ *
+ * This software is governed by the CeCILL license under French law and
+ * abiding by the rules of distribution of free software.  You can  use,
+ * modify and/ or redistribute the software under the terms of the CeCILL
+ * license as circulated by CEA, CNRS and INRIA at the following URL
+ * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html".
+ *
+ * As a counterpart to the access to the source code and  rights to copy,
+ * modify and redistribute granted by the license, users are provided only
+ * with a limited warranty  and the software's author,  the holder of the
+ * economic rights,  and the successive licensors  have only  limited
+ * liability.
+ *
+ * In this respect, the user's attention is drawn to the risks associated
+ * with loading,  using,  modifying and/or developing or reproducing the
+ * software by the user in light of its specific status of free software,
+ * that may mean  that it is complicated to manipulate,  and  that  also
+ * therefore means  that it is reserved for developers  and  experienced
+ * professionals having in-depth computer knowledge. Users are therefore
+ * encouraged to load and test the software's suitability as regards their
+ * requirements in conditions enabling the security of their systems and/or
+ * data to be ensured and,  more generally, to use and operate it in the
+ * same conditions as regards security.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL license and that you accept its terms.
+ *
+ */
+
+package fr.inrae.toulouse.metexplore.met4j_io.tabulated.network;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class Tab2BioNetworkTest {
+
+    private Tab2BioNetwork app;
+
+    @Before
+    public void init() {
+        app = new Tab2BioNetwork("test", 0, 1,
+                false, false, "_b",
+                "->", "<->", false,
+                "c", 0);
+    }
+
+
+    @Test
+    public void testLine() {
+
+        String line = "r\tm1 + 2 m2 -> m3 + m4";
+
+        assertTrue(app.testLine(line, 1));
+    }
+
+    @Test
+    public void testLineIdEmpty() {
+        String line = "  \tm1 + 2 m2 -> m3 + m4\n";
+
+        assertFalse(app.testLine(line, 1));
+    }
+
+    @Test
+    public void testBadFormulaLeft() {
+        String line = "  \tm1 + 2 a m2 -> m3 + m4\n";
+
+        assertFalse(app.testLine(line, 1));
+    }
+
+    @Test
+    public void testBadFormulaRight() {
+        String line = "  \tm1 + 2 m2 -> m3  m4\n";
+
+        assertFalse(app.testLine(line, 1));
+    }
+
+    @Test
+    public void testEmptyFormula() {
+        String line = "r\t\ttruc\n";
+
+        assertFalse(app.testLine(line, 1));
+    }
+
+    @Test
+    public void testFormulaWithoutArrow() {
+        String line = "r\ttruc + machin\n";
+
+        assertFalse(app.testLine(line, 1));
+    }
+
+    @Test
+    public void testBadNumberOfColumns() {
+
+        String line = "r\n";
+
+        assertFalse(app.testLine(line, 1));
+
+    }
+
+    @Test
+    public void testDuplicated() {
+
+        String line = "r\tm1 + 2 m2 <-> m3 + m4";
+        assertTrue(app.testLine(line, 1));
+        assertFalse(app.testLine(line, 1));
+
+    }
+
+    @Test
+    public void testFormulaWithCompartment() {
+        String line = "r\t[c] : m1 + 2 m2 <-> m3 + m4";
+        assertTrue(app.testLine(line, 1));
+    }
+
+    @Test
+    public void parseLine() {
+        String line = "r\tm1 + 2 m2 -> m3 + 3 m4";
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+
+        assertEquals(1, network.getReactionsView().size());
+        assertEquals(4, network.getMetabolitesView().size());
+        assertEquals(1, network.getCompartmentsView().size());
+        assertTrue(network.getReactionsView().containsId("r"));
+
+        BioReaction reaction = network.getReactionsView().get("r");
+
+        assertEquals(2, reaction.getLeftReactantsView().size());
+        assertEquals(2, reaction.getRightReactantsView().size());
+
+        BioReactant l1 = reaction.getLeftReactantsView().stream()
+                .filter(reactant -> reactant.getMetabolite().getId().equals("m2"))
+                .findFirst().get();
+
+        assertEquals(2, l1.getQuantity(), 0.0);
+
+        BioReactant r1 = reaction.getRightReactantsView().stream()
+                .filter(reactant -> reactant.getMetabolite().getId().equals("m4"))
+                .findFirst().get();
+
+        assertEquals(3, r1.getQuantity(), 0.0);
+
+        assertFalse(reaction.isReversible());
+
+    }
+
+    @Test
+    public void parseLineReversible() {
+        String line = "r\tm1 + 2 m2 <-> m3 + 3 m4";
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+        BioReaction reaction = network.getReactionsView().get("r");
+        assertTrue(reaction.isReversible());
+    }
+
+    @Test
+    public void parseLineEmptySide() {
+        String line = "r\t <-> ";
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+        assertEquals(1, network.getReactionsView().size());
+        assertEquals(0, network.getMetabolitesView().size());
+    }
+
+    @Test
+    public void parseLineWithCompartment() {
+        String line = "r\t[p] : m1 + 2 m2 -> m3 + 3 m4";
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+
+        assertEquals(1, network.getReactionsView().size());
+        assertEquals(4, network.getMetabolitesView().size());
+        assertEquals(1, network.getCompartmentsView().size());
+        assertTrue(network.getCompartmentsView().containsId("p"));
+
+    }
+
+    @Test
+    public void parseLineWithCompartments() {
+        String line = "r\tm1_c + 2 m2[p] -> m3_x + 3 m4_r";
+
+        app = new Tab2BioNetwork("test", 0, 1,
+                false, false, "_b",
+                "->", "<->", true,
+                "c", 0);
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+
+        assertEquals(1, network.getReactionsView().size());
+        assertEquals(4, network.getMetabolitesView().size());
+        assertEquals(4, network.getCompartmentsView().size());
+        assertTrue(network.getCompartmentsView().containsId("p"));
+        assertTrue(network.getCompartmentsView().containsId("c"));
+        assertTrue(network.getCompartmentsView().containsId("r"));
+        assertTrue(network.getCompartmentsView().containsId("x"));
+
+    }
+
+    @Test
+    public void parseLineWithFormatMetaboliteCobra() {
+        String line = "r\tm1_c + 2 m2[p] -> m3_x + 3 m4_r";
+
+        app = new Tab2BioNetwork("test", 0, 1,
+                false, true, "_b",
+                "->", "<->", true,
+                "c", 0);
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+
+        assertEquals(4, network.getMetabolitesView().size());
+        assertTrue(network.getMetabolitesView().containsId("M_m1_c"));
+        assertTrue(network.getMetabolitesView().containsId("M_m2_p"));
+        assertTrue(network.getMetabolitesView().containsId("M_m3_x"));
+        assertTrue(network.getMetabolitesView().containsId("M_m4_r"));
+    }
+
+    @Test
+    public void parseLineWithFormatReactionCobra() {
+        String line = "r\tm1_c + 2 m2[p] -> m3_x + 3 m4_r";
+
+        app = new Tab2BioNetwork("test", 0, 1,
+                true, true, "_b",
+                "->", "<->", true,
+                "c", 0);
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+        assertEquals(1, network.getReactionsView().size());
+
+        assertTrue(network.getReactionsView().containsId("R_r"));
+    }
+
+    @Test
+    public void parseSeveralLines() {
+
+        String line = "r\tm1 + 2 m2 <-> m3 + 3 m4";
+
+        app.parseLine(line, 1);
+
+        line = "r2\tm1 + 2 m2 <-> m3 + 3 m5";
+
+        app.parseLine(line, 1);
+
+        BioNetwork network = app.getBioNetwork();
+        assertEquals(2, network.getReactionsView().size());
+        assertEquals(5, network.getMetabolitesView().size());
+
+    }
+}
\ No newline at end of file
diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/AbstractSbmlSetAny.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/AbstractSbmlSetAny.java
index e1468903d26c38346e7821188a30707c49b180b9..c62e3ce2abc4d29dd7b6bb21380201e1d9a68e56 100644
--- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/AbstractSbmlSetAny.java
+++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/AbstractSbmlSetAny.java
@@ -36,6 +36,7 @@
 
 package fr.inrae.toulouse.metexplore.met4j_toolbox.attributes;
 
+import fr.inrae.toulouse.metexplore.met4j_io.tabulated.attributes.EntityType;
 import org.kohsuke.args4j.Option;
 
 /**
@@ -58,8 +59,8 @@ public abstract class AbstractSbmlSetAny extends AbstractSbmlSet {
     @Option(name="-s", usage="[deactivated] To match the objects in the sbml file, adds the suffix _comparmentID to metabolites")
     protected Boolean s=false;
 
-    @Option(name="-o", usage="[R] Object type in the column id. R:reaction;M:metabolite;P:protein;G:gene")
-    protected String o="R";
+    @Option(name="-o", usage="[REACTION] Object type in the column id : REACTION;METABOLITE;PROTEIN;GENE;PATHWAY")
+    protected EntityType o= EntityType.REACTION;
 
     /**
      * <p>Constructor for AbstractSbmlSetAny.</p>