Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deserialization bug in Spring Boot 3.2.11 #42892

Closed
davidbuzatto opened this issue Oct 25, 2024 · 3 comments
Closed

Deserialization bug in Spring Boot 3.2.11 #42892

davidbuzatto opened this issue Oct 25, 2024 · 3 comments
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid

Comments

@davidbuzatto
Copy link

When updating from spring boot 3.2.8 to 3.2.11 an error started to show when I try to persist an object. I tried the 3.2.10 version and the error disapeared. It seems like a bug, since my code stopped to work in 3.2.11.

The error is related to a composite entity. A simplified version of my scenario is as follows:

Spring Boot:

@Entity
public class Estado {
    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;
    private String nome;
    private String sigla;
}

@Entity
public class Cidade {
    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    private Long id;
    private String name;
    private Estado estado;
}

@RepositoryRestResource( collectionResourceRel = "cidades", path = "cidades", excerptProjection = CidadeInfo.class )
public interface CidadeRepository extends JpaRepository<Cidade , Long> {
}

When trying to persist a Cidade (city) which have an Estado (state/province), the following error appeared:

POST method:

JSON parse error: Cannot construct instance of br.com.studiocore.companion.entidades.Estado (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('/api/estados/1')

PATCH method:

Could not read payload

My JavaScript code:

const obj = new Cidade( 
    hdId.value === "" ? null : hdId.value, 
    txtNome.value,
    contextPath + "api/estados/" + selEstado.value
);

const id = hdId.value ? hdId.value : null;

fetch( contextPath + "api/cidades" + ( id ? `/${id}` : "" ), {
    method: id ? "PATCH" : "POST",
    headers: {
        "Authorization": "Bearer " + localStorage.getItem( "token" ),
        "Accept": "application/json",
        "Content-Type": "application/json"
    },
    body: JSON.stringify( obj )
}).then( response => {
    modalAguarde.hide();
    if ( response.ok ) {
        return response.json();
    }
    response.text().then( text => {
        let error = JSON.parse( text );
        let mensagem = "<p>Ocorreu um erro ao tentar salvar uma Cidade!</p>";
        mensagem += `<p>${error.message}</p>`;
        Utils.abrirModalMensagem( "Erro", mensagem );
    });
    throw new Error( "" );
}).then( data => {
    resetarFormulario();
    carregar( paginaAtual.pagina );
}).catch( error => {
    Utils.mostrarErro( error );
});

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Oct 25, 2024
@bclozel
Copy link
Member

bclozel commented Oct 25, 2024

Please share a minimal sample application that reproduces the problem.

Because it involves JSON deserialisation, maybe we don't need to include JPA nor any JavaScript (a simple curl command should work).

@bclozel bclozel added the status: waiting-for-feedback We need additional information before we can continue label Oct 25, 2024
@davidbuzatto
Copy link
Author

Here is the sample app: https://github.com/davidbuzatto/isthisabug

3.2.8 and 3.2.10:

POST:
curl -d "{\"bar\":\"bars/1\"}" -H "Content-Type: application/json" -X POST http://localhost:8080/foos

Response OK:

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/foos/2"
    },
    "foo" : {
      "href" : "http://localhost:8080/foos/2"
    },
    "bar" : {
      "href" : "http://localhost:8080/foos/2/bar"
    }
  }
}

PATCH:
curl -d "{\"bar\":\"bars/1\"}" -H "Content-Type: application/json" -X PATCH http://localhost:8080/foos/1

Response OK:

{
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/foos/1"
    },
    "foo" : {
      "href" : "http://localhost:8080/foos/1"
    },
    "bar" : {
      "href" : "http://localhost:8080/foos/1/bar"
    }
  }
}

3.2.11:

POST:
curl -d "{\"bar\":\"bars/1\"}" -H "Content-Type: application/json" -X POST http://localhost:8080/foos

Error:
{"cause":{"cause":null,"message":"Cannot construct instance of com.example.demo.Bar(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('bars/1')\n at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 8] (through reference chain: com.example.demo.Foo[\"bar\"])"},"message":"JSON parse error: Cannot construct instance ofcom.example.demo.Bar(although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('bars/1')"}

PATCH:
curl -d "{\"bar\":\"bars/1\"}" -H "Content-Type: application/json" -X PATCH http://localhost:8080/foos/1

Error:

{"cause":{"cause":null,"message":"Cannot construct instance of com.example.demo.Bar (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('bars/1')\n at [Source: UNKNOWN; byte offset: #UNKNOWN] (through reference chain: com.example.demo.Foo[\"bar\"])"},"message":"Could not read payload"}

@spring-projects-issues spring-projects-issues added status: feedback-provided Feedback has been provided and removed status: waiting-for-feedback We need additional information before we can continue labels Oct 25, 2024
@bclozel
Copy link
Member

bclozel commented Oct 26, 2024

Thanks for the sample, I think this is a regression in Spring Data. Using Spring Boot 3.2.11 but downgrading Spring Data works:

    <properties>
        <spring-data-bom.version>2023.1.10</spring-data-bom.version>
    </properties>

I think this has been reported already in spring-projects/spring-data-rest#2425 so I'm closing this issue as a duplicate.

@bclozel bclozel closed this as not planned Won't fix, can't repro, duplicate, stale Oct 26, 2024
@bclozel bclozel added status: invalid An issue that we don't feel is valid for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged status: feedback-provided Feedback has been provided labels Oct 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix status: invalid An issue that we don't feel is valid
Projects
None yet
Development

No branches or pull requests

3 participants