在Spark 3.4.0中,Encoders.bean不再在JavaPOJO上工作

mo49yndu  于 2023-04-19  发布在  Java
关注(0)|答案(1)|浏览(156)

这种方法从Spark 3.2.x到Spark 3.3.x都运行良好,

public Dataset<Commune> obtenirCommunes(SparkSession session, int anneeCOG) throws TechniqueException {
   Dataset<Row> communes = rowCommunes(session, anneeCOG);

   return communes
      .select(communes.col("typeCommune"), communes.col("codeCommune"), communes.col("codeRegion"), communes.col("codeDepartement"),
          communes.col("arrondissement"), communes.col("typeNomEtCharniere"), communes.col("nomMajuscules"), communes.col("nomCommune"), 
          communes.col("codeCanton"), communes.col("codeCommuneParente"), communes.col("sirenCommune"), communes.col("populationTotale").alias("population"),
          communes.col("strateCommune"), communes.col("codeEPCI"), communes.col("surface"), communes.col("longitude"), communes.col("latitude"),
          communes.col("nomDepartement"), communes.col("nomEPCI"))
      .as(Encoders.bean(Commune.class))
      .cache();
   }

现在Spark 3.4.0失败了,通过这个测试:

/**
 * Charger le Code Officiel Géographique entier.
 * @throws CommuneInexistanteException si la commune recherchée n'existe pas.
 * @throws TechniqueException si un incident survient.
 */
@Test
@DisplayName("Lecture du code officiel géographique")
void cog() throws TechniqueException, CommuneInexistanteException {
   for(int cog = COG_START; cog <= COG_END; cog ++) {
      if (this.toutesAnnees == false && cog != COG_END) {
         continue;
      }
         
      CodeOfficielGeographique maillage = this.cogDataset.obtenirCodeOfficielGeographique(this.session, cog, true);
      LOGGER.info("Code Officiel Géographique : {} communes, {} intercommunalités.", maillage.getCommunes().size(), maillage.getIntercommunalites().size());
         
      Intercommunalite intercommunalite = maillage.getIntercommunalites().values().iterator().next();
      LOGGER.info("La première intercommunalité : {}", intercommunalite);
         
      Commune cambremer = maillage.getCommune("14126");
      assertNotNull(cambremer, MessageFormat.format("Cambremer aurait dû être trouvé dans le COG {0}.", cog));
      LOGGER.info(cambremer.toString());
   }
}

失败伴随着一个不太清楚的日志(它是调用失败的CogDataset:obtenirCommunes的行CodeOfficielGeographique maillage = this.cogDataset.obtenirCodeOfficielGeographique(this.session, cog, true)):

java.util.NoSuchElementException: None.get

    at scala.None$.get(Option.scala:627)
    at scala.None$.get(Option.scala:626)
    at org.apache.spark.sql.catalyst.ScalaReflection$.$anonfun$deserializerFor$8(ScalaReflection.scala:359)
    at scala.collection.immutable.ArraySeq.map(ArraySeq.scala:75)
    at scala.collection.immutable.ArraySeq.map(ArraySeq.scala:35)
    at org.apache.spark.sql.catalyst.ScalaReflection$.deserializerFor(ScalaReflection.scala:348)
    at org.apache.spark.sql.catalyst.ScalaReflection$.deserializerFor(ScalaReflection.scala:183)
    at org.apache.spark.sql.catalyst.encoders.ExpressionEncoder$.apply(ExpressionEncoder.scala:56)
    at org.apache.spark.sql.catalyst.encoders.ExpressionEncoder$.javaBean(ExpressionEncoder.scala:62)
    at org.apache.spark.sql.Encoders$.bean(Encoders.scala:179)
    at org.apache.spark.sql.Encoders.bean(Encoders.scala)
    at fr.ecoemploi.spark.dataset.cog.CogDataset.obtenirCommunes(CogDataset.java:220)
    at fr.ecoemploi.spark.dataset.cog.CogDataset.obtenirCodeOfficielGeographique(CogDataset.java:186)
    at fr.ecoemploi.spark.dataset.cog.CommuneObjectsMetiersIT.cog(CommuneObjectsMetiersIT.java:92)

Encoders.bean的目标对象Commune是这样的:

package fr.ecoemploi.metier.territoire;

import static fr.ecoemploi.metier.territoire.PrefixageNomCommune.*;

import java.io.Serial;
import java.text.*;
import java.util.*;
import java.util.function.Predicate;

import javax.validation.constraints.*;

import org.apache.commons.lang3.*;

import fr.fondation.utilitaires.autocontrole.*;
import fr.fondation.utilitaires.localisation.*;
import io.swagger.v3.oas.annotations.*;
import io.swagger.v3.oas.annotations.media.*;

/**
 * Une commune.
 * @author Marc LE BIHAN.
 */
@Schema(description = "Une commune du Code Officiel Géographique")
public class Commune extends ObjetMetierSpark {
   /** Serial ID */
   @Serial
   private static final long serialVersionUID = 4381577514414536917L;

   /** Collator utilisé pour comparer les noms de communes, sans accents. */
   private static final Collator collator = Collator.getInstance(Locale.FRENCH);
   
   static {
      collator.setStrength(Collator.PRIMARY);
   }

   /** Code de la commune. */
   @NotNull @Size(min = 5, max = 5) @Schema(description = "Code de la commune", example = "29019")
   private String codeCommune;
   
   /** Code ddépartement. */
   @NotNull @Size(min=2, max=3) @Schema(description = "Code du département", example = "972")
   private String codeDepartement;
   
   /** Nom du département. */
   @NotNull @Schema(description = "Nom du département", example = "Finistère")
   private String nomDepartement;

   /** Code de la commune parente (pour arrondissements, communes associées ou déléguées). */
   @Size(min = 9, max = 9) @Schema(description = "Code de la commune parente", example = "75056", nullable = true)
   private String codeCommuneParente;

   /** Code INSEE de la région auquel appartient ce département. */
   @NotNull @Size(min = 2, max = 2) @Schema(description = "Code de la région", example = "84")
   private String codeRegion;
   
   /** Code Canton de la commune. */
   @Schema(description = "Code du canton", nullable = true)
   private String codeCanton;

   /** Nom de la ville. */
   @NotNull @Schema(description = "Nom de la commune", example = "Brest")
   private String nomCommune;

   /** Nom en majuscule. */
   @NotNull @Schema(description = "Nom de la commune en majuscules", example = "BREST")
   private String nomMajuscules;

   /** Type et nom charnière. */
   @NotNull @Size(min=1, max=1)
   @Schema(description = "Type de nom et charnière: <ul>"
         + "<li>0  Pas d'article et le nom commence par une consonne sauf H muet  charnière = DE</li>"
         + "<li>1  Pas d'article et le nom commence par une voyelle ou un H muet  charnière = D'</li>"
         + "<li>2  Article = LE   charnière = DU</li>"
         + "<li>3  Article = LA   charnière = DE LA</li>"
         + "<li>4  Article = LES  charnière = DES</li>"
         + "<li>5  Article = L'   charnière = DE L'</li>"
         + "<li>6  Article = AUX  charnière = DES</li>"
         + "<li>7  Article = LAS  charnière = DE LAS</li>"
         + "<li>8  Article = LOS  charnière = DE LOS</li>"
         + "</ul>")
   private String typeNomEtCharniere;

   /** SIREN de la commune (permet de la lier à son intercommunalité). */
   @NotNull @Size(min=9, max=9) @Schema(description = "Numéro SIREN de la commune", example = "212900195")
   private String sirenCommune;

   /** Liste des groupements dont cette commune est le siège. */
   @NotNull 
   @Schema(description = "Liste des groupements (EPCI, ultérieurement : syndicats) dont cette commune est le siège. "
         + "Cette liste est vide si la commune n'est siège d'aucun syndicat ou intercommunalité.", example = "[242900314]")
   private Set<String> siegeGroupements = new HashSet<>();
   
   /** Liste des intercommunalités dont cette commune est membre. */
   @NotNull @Schema(description = "Liste des groupepements (EPCI, ultérieurement : syndicats) dont cette commune est membre.", example = "[242900314]")
   private Set<String> membreGroupements = new HashSet<>();
   
   /** Intercommunalité à fiscalité propre à laquelle cette commune appartient (qu'elle en soit siège ou membre). */
   @NotNull @Size(min=9, max=9) @Schema(description = "Numéro SIREN de l'intercommunalité dont cette commune est siège ou membre.", example = "242900314")
   private String epciFiscalitePropre;
   
   /** Nom de de l'intercommunalité à laquelle la commune appartient. */
   @NotNull @Schema(description = "Nom de l'intercommunalité à laquelle la commune appartient", example = "Brest Métropole")
   private String nomEPCI;
   
   /** Arrondissement de la commune. */
   @Schema(description = "Code de l'arrondissement de la commune.", nullable = true)
   private String arrondissement;
   
   /** Population de la commune. */
   @NotNull @Schema(description = "Population totale de la commune.")
   private Integer population;
   
   /** Type de la commune. */
   @NotNull
   @Schema(description = "Type de la commune : <ul>" +
      "<li>COM   Commune</li>" + 
      "<li>COMA  Commune associée</li>" + 
      "<li>COMD  Commune déléguée</li>" + 
      "<li>ARM   Arrondissement municipal</li>"
      + "</ul>", example = "COM")
   private String typeCommune;
   
   /** Strate communale. */
   @NotNull
   @Schema(description = "Strate communale : <ul>" +
         "<li>1 : Moins de 100 habitants</li>" + 
         "<li>2 : De 100 à moins de 200 habitants</li>" + 
         "<li>3 : De 200 à moins de 500 habitants</li>" + 
         "<li>4 : De 500 à moins de 2 000 habitants</li>" + 
         "<li>5 : De 2 000 à moins de 3 500 habitants</li>" + 
         "<li>6 : De 3 500 à moins de 5 000 habitants</li>" + 
         "<li>7 : De 5 000 à moins de 10 000 habitants</li>" + 
         "<li>8 : de 10 000 à moins de 20 000 habitants</li>" + 
         "<li>9 : de 20 000 à moins de 50 000 habitants</li>" + 
         "<li>10 : de 50 000 à moins de 100 000 habitants</li>" + 
         "<li>11 : 100 000 habitants et plus</li>" + 
         "</ul>", example = "1")
   private Integer strateCommune;
   
   /** Surface de la commune en hectares. */
   @Schema(description = "Surface de la commune, en hectares. N'est pas alimenté pour les arrondissements.", example = "1520.25", nullable = true)
   private Double surface;
   
   /** Longitude du centroïde de la commune. */
   @Schema(description = "Longitude du centroïde de la commune. N'est pas alimenté pour les arrondissements.", example = "-4.2908", nullable = true)
   private Double longitude;
   
   /** Latitude du centroïde de la commune. */
   @Schema(description = "Latitude du centroïde de la commune. N'est pas alimenté pour les arrondissements.", example = "48.2327", nullable = true)
   private Double latitude;

   /**
    * Construire une commune.
    */
   public Commune() {
   }
   
   /**
    * Ajouter une intercommunalité dont cette commune est membre.
    * @param sirenIntercommunalite SIREN de l'intercommunalité.
    */
   public void ajouterMembreGroupement(String sirenIntercommunalite) {
      this.membreGroupements.add(sirenIntercommunalite);
   }
   
   /**
    * Ajouter une intercommunalité dont cette commune est le siège.
    * @param sirenIntercommunalite SIREN de l'intercommunalité.
    */
   public void ajouterSiegeGroupement(String sirenIntercommunalite) {
      this.siegeGroupements.add(sirenIntercommunalite);
   }

   /**
    * Renvoyer le code Canton de la commune. 
    * @return Code canton de la commune.
    */
   public String getCodeCanton() {
      return this.codeCanton;
   }

   /**
    * Fixer le code canton de la commune.
    * @param codeCanton Code canton de la commune.
    */
   public void setCodeCanton(String codeCanton) {
      this.codeCanton = codeCanton;
   }

   /**
    * Renvoyer le code de la commune.
    * @return Code de la commune.
    */
   public String getCodeCommune() {
      return this.codeCommune;
   }

   /**
    * Renvoyer le code de la commune.
    * @return Code de la commune.
    */
   public CodeCommune astCodeCommune() {
      return new CodeCommune(this.codeCommune);
   }

   /**
    * Renvoyer le code commune parente (pour arrondissements, communes associées ou déléguées).
    * @return Code commune parente.
    */
   public CodeCommune astCodeCommuneParente() {
      return new CodeCommune(this.codeCommuneParente);
   }
   
   /**
    * Renvoyer le code commune parente (pour arrondissements, communes associées ou déléguées).
    * @return Code commune parente.
    */
   public String getCodeCommuneParente() {
      return this.codeCommuneParente;
   }

   /**
    * Renvoyer le code département.
    * @return Code département.
    */
   public CodeDepartement asCodeDepartement() {
      return new CodeDepartement(this.codeDepartement);
   }

   /**
    * Renvoyer le code département.
    * @return Code département.
    */
   public String getCodeDepartement() {
      return this.codeDepartement;
   }

   /**
    * Renvoyer le code région.
    * @return Code région.
    */
   public CodeRegion asCodeRegion() {
      return new CodeRegion(this.codeRegion);
   }

   /**
    * Renvoyer le code région.
    * @return Code région.
    */
   public String getCodeRegion() {
      return this.codeRegion;
   }
   
   /**
    * Renvoyer l'intercommunalité à fiscalité propre à laquelle cette commune appartient, qu'elle en soit siège ou membre.
    * @return Intercommunalité.
    */
   public SIREN asEpciFiscalitePropre() {
      return new SIREN(this.epciFiscalitePropre);
   }

   /**
    * Renvoyer l'intercommunalité à fiscalité propre à laquelle cette commune appartient, qu'elle en soit siège ou membre.
    * @return Intercommunalité.
    */
   @Hidden
   public String getCodeEPCI() {
      return this.epciFiscalitePropre;
   }

   /**
    * Fixer l'intercommunalité à fiscalité propre à laquelle cette commune appartient, qu'elle en soit siège ou membre.
    * @param epci Intercommunalité.
    */
   @Hidden
   public void setCodeEPCI(String epci) {
      this.epciFiscalitePropre = epci;
   }

   /**
    * Renvoyer les groupements dont cette commune est membre.
    * @return Groupements.
    */
   public Set<String> membreGroupements() {
      return this.membreGroupements;
   }

   /**
    * Renvoyer la liste des groupements dont cette commune est le siège.
    * @return liste des groupements.
    */
   public Set<String> siegeGroupements() {
      return this.siegeGroupements;
   }
   
   /**
    * Renvoyer l'arrondissement.
    * @return Arrondissement.
    */
   public String getArrondissement() {
      return this.arrondissement;
   }
   
   /**
    * Déterminer si ce code commune désigne une collectivité d'outre-mer :<br>
    * Attention, il s'agit des départements 975, 977, 978 et 98, et pas les départements d'outremer 971, 972, 973, 974 et 976.
    * @return true si c'est le cas.
    */
   @Hidden
   public boolean isCollectiviteOutremer() {
      return this.codeCommune != null &&
         (this.codeCommune.startsWith("975") || this.codeCommune.startsWith("977") || this.codeCommune.startsWith("978") || this.codeCommune.startsWith("98"));
   }

   /**
    * Fixer l'arrondissement.
    * @param arrondissement Arrondissement.
    */
   public void setArrondissement(String arrondissement) {
      this.arrondissement = arrondissement;
   }

   /**
    * Renvoyer le nom de la commune.
    * @return Nom de la commune.
    */
   public String getNomCommune() {
      return this.nomCommune;
   }
   
   /**
    * Déterminer si notre commune a le même nom que celle en paramètre.
    * @param nomCandidat Nom de commune : il peut contenir une charnière.
    * @return true si c'est le cas.
    */
   public boolean hasMemeNom(String nomCandidat) {
      // Si le nom soumis vaut null, répondre non.
      if (nomCandidat == null) {
         return false;
      }

      // Faire une comparaison directe de nom de commune tout d'abord, car l'emploi du collator est très coûteux.
      if (nomCandidat.equalsIgnoreCase(this.nomCommune)) {
         return true;
      }
      
      // Puis, rechercher avec les différentes charnières.
      if (nomCandidat.equalsIgnoreCase(nomAvecType(false, PrefixageNomCommune.AUCUN))) {
         return true;
      }
      
      if (nomCandidat.equalsIgnoreCase(nomAvecType(false, PrefixageNomCommune.A))) {
         return true;
      }
      
      if (nomCandidat.equalsIgnoreCase(nomAvecType(false, PrefixageNomCommune.POUR))) {
         return true;
      }
      
      // En cas d'échec, reprendre ces tests, mais avec le collator, plus lent, mais qui passera outre les caractères accentués.
      if (collator.equals(nomCandidat, this.nomCommune)) {
         return true;
      }
      
      if (collator.equals(nomCandidat, nomAvecType(false, PrefixageNomCommune.AUCUN))) {
         return true;
      }
      
      if (collator.equals(nomCandidat, nomAvecType(false, PrefixageNomCommune.A))) {
         return true;
      }

      if (collator.equals(nomCandidat, nomAvecType(false, PrefixageNomCommune.POUR))) {
         return true;
      }

      // Alternative aux tests précédents
      List<Predicate<String>> memeNoms = new ArrayList<>();
      memeNoms.add(nom -> nom.equalsIgnoreCase(nomAvecType(false, PrefixageNomCommune.AUCUN)));
      memeNoms.add(nom -> nom.equalsIgnoreCase(nomAvecType(false, PrefixageNomCommune.A)));
      memeNoms.add(nom -> nom.equalsIgnoreCase(nomAvecType(false, PrefixageNomCommune.POUR)));
      memeNoms.add(nom -> collator.equals(nom, this.nomCommune));
      memeNoms.add(nom -> collator.equals(nom, nomAvecType(false, PrefixageNomCommune.AUCUN)));
      memeNoms.add(nom -> collator.equals(nom, nomAvecType(false, PrefixageNomCommune.A)));
      memeNoms.add(nom -> collator.equals(nom, nomAvecType(false, PrefixageNomCommune.POUR)));

      return memeNoms.stream().anyMatch(memeNom -> memeNom.test(nomCandidat));
   }

   /**
    * Renvoyer le nom de la commune avec sa charnière accolée : Ville D'Ermenouville, Ville de Villenoy
    * @param majuscules true S'il faut que la ville et sa charnière soient en majuscules.
    * @return Nom de la commune avec sa charnière.
    */
   public String nomAvecCharniere(boolean majuscules) {
      String articleCommune = switch(asArticleEtCharniere()) {
         case AUCUN_D_APOSTROPHE -> "d'";
         case AUX_DES, LES_DES -> "des ";
         case LAS_DE_LAS -> "de las ";
         case LA_DE_LA -> "de la ";
         case LE_DU -> "du ";
         case LOS_DE_LOS -> "de los ";
         case L_APOSTROPHE_DE_L_APOSTROPHE -> "l'";
         default -> // inclut le cas : AUCUN_CONSONNE_DE
            "de ";
      };

      String texte = articleCommune + (majuscules ? this.nomMajuscules : this.nomCommune);
      return majuscules ? texte.toUpperCase(Locale.FRENCH) : texte;
   }

   /**
    * Renvoyer le nom de la commune avec son type accolé : Bienvenue à Ermenouville, Bienvenue aux Ullis.
    * @param majuscules true S'il faut que la ville et sa charnière soient en majuscules.
    * @param prefixage Indique s'il faut replacer type vide par 'à', 'pour' : "Bienvenue à St-Etienne", "pour les Ullis".
    * @return Nom de la commune avec sa charnière.
    */
   public String nomAvecType(boolean majuscules, PrefixageNomCommune prefixage) {
      String articleCommune = "";
      String prefixe = "";

      final String PREFIXE_POUR = "pour ";

      switch(asArticleEtCharniere()) {
         case AUCUN_CONSONNE_DE -> {
            if (prefixage.equals(A))
               articleCommune = "à ";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         case AUCUN_D_APOSTROPHE -> {
            if (prefixage.equals(A))
               prefixe = "à ";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         case AUX_DES -> articleCommune = "aux ";

         case LAS_DE_LAS -> {
            articleCommune = "las ";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         case LA_DE_LA -> {
            articleCommune = "la ";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         case LES_DES -> {
            articleCommune = "les ";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         case LE_DU -> {
            articleCommune = "le ";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         case LOS_DE_LOS -> {
            articleCommune = "los ";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         case L_APOSTROPHE_DE_L_APOSTROPHE -> {
            articleCommune = "l'";

            if (prefixage.equals(POUR))
               prefixe = PREFIXE_POUR;
         }

         default -> {
            if (prefixage.equals(A))
               prefixe = "à ";
         }
      }

      String texte = prefixe + articleCommune + (majuscules ? this.nomMajuscules : this.nomCommune);
      return majuscules ? texte.toUpperCase(Locale.FRENCH) : texte;
   }

   /**
    * Renvoyer le nom de la commune en majuscules.
    * @return Nom de la commune.
    */
   public String getNomMajuscules() {
      return this.nomMajuscules;
   }
   
   /**
    * Obtenir la population de la commune une année particulière.
    * @return population de la commune.
    */
   public Integer getPopulation() {
      return this.population;
   }

   /**
    * Convertit un type de nom INSEE en enum charnière INSEE.
    * @return Enumération.
    */
   public ArticleEtCharniereINSEE asArticleEtCharniere() {
      for(ArticleEtCharniereINSEE candidat : ArticleEtCharniereINSEE.values()) {
         if (candidat.getCode().equals(this.typeNomEtCharniere))
            return candidat;
      }

      return null;
   }
   
   /**
    * Renvoyer l'article et la charnière.
    * @return Article et charnière.
    */
   public String getTypeNomEtCharniere() {
      return this.typeNomEtCharniere;
   }
   
   /**
    * Déterminer si la commune a un numéro de SIREN alimenté
    * (elle en a forcément un, mais parfois l'objet métier ne le porte pas encore).
    * @return true, si c'est le cas.
    */
   public boolean hasSIREN() {
      return this.sirenCommune != null && StringUtils.isBlank(this.sirenCommune) == false;
   }

   /**
    * Fixer le code de la commune.
    * @param code Code de la commune.
    */
   public void setCodeCommune(String code) {
      this.codeCommune = code;
   }

   /**
    * Fixer le code de la commune parente (pour arrondissements, communes associées ou déléguées).
    * @param code Code de la commune parente (pour arrondissements, communes associées ou déléguées).
    */
   public void setCodeCommuneParente(String code) {
      this.codeCommuneParente = code;
   }

   /**
    * Fixer le code département.
    * @param code Code département.
    */
   public void setCodeDepartement(String code) {
      this.codeDepartement = code;
   }

   /**
    * Fixer le code région.
    * @param code Code région.
    */
   public void setCodeRegion(String code) {
      this.codeRegion = code;
   }

   /**
    * Fixer les groupements dont cette commune est membre.
    * @param groupements Groupements.
    */
   public void membreGroupements(Set<String> groupements) {
      this.membreGroupements = groupements;
   }
   
   /**
    * Fixer les groupements dont cette commune est le siège.
    * @param siegeIntercommunalites Intercommunalités.
    */
   public void siegeGroupements(Set<String> siegeIntercommunalites) {
      this.siegeGroupements = siegeIntercommunalites;
   }

   /**
    * Renvoyer la latitude de la commune.
    * @return Latitude de la commune.
    */
   public Double getLatitude() {
      return this.latitude;
   }

   /**
    * Fixer la latitude de la commune.
    * @param latitude Latitude de la commune.
    */
   public void setLatitude(Double latitude) {
      this.latitude = latitude;
   }

   /**
    * Renvoyer la longitude de la commune.
    * @return Longitude de la commune.
    */
   public Double getLongitude() {
      return this.longitude;
   }

   /**
    * Fixer la longitude de la commune.
    * @param longitude Longitude de la commune. 
    */
   public void setLongitude(Double longitude) {
      this.longitude = longitude;
   }
   
   /**
    * Renvoyer le nom du département.
    * @return Nom du département.
    */
   public String getNomDepartement() {
      return this.nomDepartement;
   }
   
   /**
    * Fixer le nom du département.
    * @param nomDepartement Nom du département.
    */
   public void setNomDepartement(String nomDepartement) {
      this.nomDepartement = nomDepartement;
   }
   
   /**
    * Renvoyer le nom de l'EPCI dont la commune est membre ou siège.
    * @return Nom de l'EPCI.
    */
   public String getNomEPCI() {
      return this.nomEPCI;
   }

   /**
    * Fixer le nom de l'EPCI dont la commune est membre ou siège.
    * @param nomEPCI Nom de l'EPCI.
    */
   public void setNomEPCI(String nomEPCI) {
      this.nomEPCI = nomEPCI;
   }

   /**
    * Fixer le nom de la ville.
    * @param nomVille Nom de la ville.
    */
   public void setNomCommune(String nomVille) {
      this.nomCommune = nomVille;
   }

   /**
    * Fixer le nom de la commune en majuscules.
    * @param nomVille Nom de la commune.
    */
   public void setNomMajuscules(String nomVille) {
      this.nomMajuscules = nomVille;
   }
   
   /**
    * Fixer la population de la commune une année donnée.
    * @param population Population.
    */
   public void setPopulation(Integer population) {
      this.population = population;
   }

   /**
    * Renvoyer le SIREN de la commune.
    * @return SIREN.
    */
   public SIRENCommune asSiren() {
      return new SIRENCommune(this.sirenCommune);
   }

   /**
    * Renvoyer le SIREN de la commune.
    * @return SIREN.
    */
   public String getSirenCommune() {
      return this.sirenCommune;
   }

   /**
    * Fixer le code SIREN de la commune.
    * @param sirenCommune Siren.
    */
   public void setSirenCommune(String sirenCommune) {
      this.sirenCommune = sirenCommune;
   }
   
   /**
    * Renvoyer la strate communale.
    * @return Strate :<br>
    * 1 : Moins de 100 habitants<br> 
    * 2 : De 100 à moins de 200 habitants<br>
    * 3 : De 200 à moins de 500 habitants<br>
    * 4 : De 500 à moins de 2 000 habitants<br>
    * 5 : De 2 000 à moins de 3 500 habitants<br>
    * 6 : De 3 500 à moins de 5 000 habitants<br>
    * 7 : De 5 000 à moins de 10 000 habitants<br>
    * 8 : de 10 000 à moins de 20 000 habitants<br>
    * 9 : de 20 000 à moins de 50 000 habitants<br>
    * 10 : de 50 000 à moins de 100 000 habitants<br>
    * 11 : 100 000 habitants et plus
    */
   public Integer getStrateCommune() {
      return this.strateCommune;
   }
   
   /**
    * Fixer la strate communale.
    * @param strate Strate communele.
    */
   public void setStrateCommune(Integer strate) {
      this.strateCommune = strate;
   }

   /**
    * Renvoyer la surface de la commune, en hectares.
    * @return Surface en hectares.
    */
   public Double getSurface() {
      return this.surface;
   }

   /**
    * Fixer la surface de la communes, en hectares.
    * @param surface Surface en hectares.
    */
   public void setSurface(Double surface) {
      this.surface = surface;
   }

   /**
    * Fixer le type nom et charnière.
    * @param type Type nom et charnière.
    */
   public void setTypeNomEtCharniere(String type) {
      this.typeNomEtCharniere = type;
   }
   
   /**
    * Renvoyer le type de commune. 
    * @return Type de commune.
    */
   public String getTypeCommune() {
      return this.typeCommune;
   }

   /**
    * Fixer le type de commune.
    * @param typeDeCommune Type de commune.
    */
   public void setTypeCommune(String typeDeCommune) {
      this.typeCommune = typeDeCommune;
   }

   /**
    * @see fr.fondation.objets.ObjetMetierIdentifiable#toString()
    */
   @Override
   public String toString() {
      return BabelTower.format(Commune.class, "toString", this.nomCommune, this.nomMajuscules, this.codeDepartement, this.codeRegion,
         this.codeCommuneParente, this.typeNomEtCharniere, this.codeCommune, this.sirenCommune, this.siegeGroupements, 
         this.membreGroupements, this.epciFiscalitePropre, this.arrondissement, this.codeCanton, this.population, this.strateCommune,
         this.surface, this.longitude, this.latitude, this.nomDepartement, this.nomEPCI);
   }
}

我的假设是,Encoders.bean改变了它在3.4.0中的工作方式,或者它的先决条件,但是我不知道它现在拒绝了什么。

uxhixvfz

uxhixvfz1#

问题始于堆栈跟踪中的private def deserializerFor(enc: AgnosticEncoder[_], path: Expression, walkedTypePath: WalkedTypePath)
它尝试运行这段代码:

case JavaBeanEncoder(tag, fields) =>
  val setters = fields.map { f =>
    val newTypePath = walkedTypePath.recordField(
      f.enc.clsTag.runtimeClass.getName,
      f.name)
    val setter = expressionWithNullSafety(
      deserializerFor(
        f.enc,
        addToPath(path, f.name, f.enc.dataType, newTypePath),
        newTypePath),
      nullable = f.nullable,
      newTypePath)
    f.writeMethod.get -> setter
  }
[...]

在这里,在其搜索中,它搜索isCollectiviteOutremer方法,并找到:

EncoderField(isCollectiviteOutremer,PrimitiveBooleanEncoder,true,{},Some(isCollectiviteOutremer),None)

(or类似的东西,我在调试中解决了它)。重要的是,对于setter它有:None
因为它尝试编码的方法是:

public boolean isCollectiviteOutremer() {
   return this.codeCommune != null &&
      (this.codeCommune.startsWith("975") || this.codeCommune.startsWith("977") || this.codeCommune.startsWith("978") || this.codeCommune.startsWith("98"));
}

这是一种实用的方法,不需要设置器。
实际上,这个方法不需要编码到字段中,但是我不知道如何告诉Encoders.bean(...)跳过它。如果存在注解,或者其他什么。
无论如何,我能够通过将其返回类型从boolean更改为Boolean来删除该编码尝试,然后我就不再有问题了:方法isCollectiviteOutremer不再列在fields中。
然而,我对这个问题的回答更多的是一种变通方法,而不是一个好的解决方案。

相关问题