Estou convivendo com uma dificuldade em gerar o arquivo xml! e o que pretendo é, gerar todas as vendas de um intervalo de datas com os respetivos produtos de cada venda, só que ao gerar ele gera apenas a última venda, parece-me que o problema esta na subconsulta( em querer gerar os produtos de cada venda).
Posta o código pra gente tentar entender o problema. (copie e cole o código aqui formatando com </>)
Este é o script:
<script type="text/javascript">
$(document).ready(function(){
$('#comboboxProvincia').on('change', function(){
alert('' + $(this).val());
var idProvincia = $(this).val();
$.ajax({
type: 'GET',
url: '/loadMunicipioByProvincia/' + idProvincia,
success: function(result) {
var result = JSON.stringify(result);
var s = '';
for(var i = 0; i < result.length; i++) {
s += '<option value="' + result[i].idMunicipio + '">' + result[i].descricaoMuni + '</option>';
}
$('#comboboxMunicipio').html(s);
}
});
});
});
</script>
essa parte não está certa:
var result = JSON.stringify(result);
No success
, dá um console.log
no result
e poste aqui o que aparece no console do navegador. Assim:
success: function(result) {
console.log(result);
}
Mas, com jquery, vc pode informar o dataType
na requisição como json
:
$(document).ready(function() {
$('#comboboxProvincia').on('change', function() {
alert('' + $(this).val());
var idProvincia = $(this).val();
$.ajax({
type: 'GET',
dataType: 'json', // <-- inclua isso que o retorno já será recebido no formato JSON
url: '/loadMunicipioByProvincia/' + idProvincia,
success: function(result) {
var s = '';
for (var i = 0; i < result.length; i++) {
// prefira template string para concatenar
s += `<option value="${result[i].idMunicipio}">${result[i].descricaoMuni}</option>`;
}
$('#comboboxMunicipio').html(s);
}
});
});
});
Este é resultado da console
1. (2) [{…}, {…}]
1. 0: {idMunicipio: 0, descricaoMuni: null, provincia: null, bairros: Array(0)}
2. 1: {idMunicipio: 0, descricaoMuni: null, provincia: null, bairros: Array(0)}
3. length: 2
4. [[Prototype]]: Array(0)
Blz, parece que o json foi retornado corretamente.
Lucas, já percebi o problema, o problema está no retorno, é que a minha função está retornar valores null:
@ResponseBody
@RequestMapping(value = "loadMunicipioByProvincia/{idProvincia}", method = RequestMethod.GET)
public List<Municipio> loadMunicipioByProvincia(@PathVariable("idProvincia") Integer idProvincia) {
System.out.println("Id da Provincia: "+idProvincia);
List<Municipio> listaNew = municipioService.listaMuniPorProv(idProvincia);
return municipioService.listaMuniPorProv(idProvincia).stream().map(m -> new Municipio()).collect(Collectors.toList());
}
Retornando simplesmente a lista:
return municipioService.listaMuniPorProv(idProvincia)
da um erro:
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:145) ~[jackson-databind-2.13.3.jar:2.13.3]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:107) ~[jackson-databind-2.13.3.jar:2.13.3]
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25) ~[jackson-databind-2.13.3.jar:2.13.3]
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.13.3.jar:2.13.3]
Tens uma outra forma para retornar a lista?
Posta o código da entidade que está sendo retornada nessa lista pra gente ver.
Lembre de formatar o ćodigo usando o botão </>
Ah cara, vi aqui o erro. Tu tah fazendo o map
errado, nessa parte:
return municipioService.listaMuniPorProv(idProvincia)
.stream()
.map(m -> new Municipio()) // tu tah fazendo o map criando um objeto vazio
.collect(Collectors.toList());
Tente retornar a lista sem fazer map:
return municipioService.listaMuniPorProv(idProvincia)
ok
Esta é a entidade município:
package co.com.SIGIHOM.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import net.bytebuddy.utility.nullability.NeverNull;
@Entity
@Table(name = "tb_municipio")
public class Municipio {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer idMunicipio;
private String descricaoMuni;
@ManyToOne
@JoinColumn(name = "idProvincia")
@NeverNull
private Provincia provincia;
@OneToMany(mappedBy = "municipio")
List<Bairro> bairros = new ArrayList<>();
public List<Bairro> getBairros() {
return bairros;
}
public void setBairros(List<Bairro> bairros) {
this.bairros = bairros;
}
public Provincia getProvincia() {
return provincia;
}
public void setProvincia(Provincia provincia) {
this.provincia = provincia;
}
public String getDescricaoMuni() {
return descricaoMuni;
}
public void setDescricaoMuni(String descricaoMuni) {
this.descricaoMuni = descricaoMuni;
}
public Integer getIdMunicipio() {
return idMunicipio;
}
public void setIdMunicipio(Integer idMunicipio) {
this.idMunicipio = idMunicipio;
}
}
Retornando a lista, esta dando este erro:
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.13.3.jar:2.13.3]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774) ~[jackson-databind-2.13.3.jar:2.13.3]
...
at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:728) ~[jackson-databind-2.13.3.jar:2.13.3]
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:774) ~[jackson-databind-2.13.3.jar:2.13.3]
Posta a entidade Provincia
também.
To achando que é o problema de relacionamento bidirecional mesmo. Ex.:
A entidade Municipio
possui uma Provincia
e uma lista de Bairro
s. Se na Provincia
tiver uma lista de Municipio
s, ou na entidade Bairro
tiver um Municipio
, a serialização vai ficar em loop e dá erro.
package co.com.SIGIHOM.model;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
@Entity
@Table(name = "tb_provincia")
public class Provincia {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer idProvincia;
private String descricaoProv;
@OneToMany(mappedBy = "provincia")
List<Municipio> municipios = new ArrayList<>();
public List<Municipio> getMunicipios() {
return municipios;
}
public void setMunicipios(List<Municipio> municipios) {
this.municipios = municipios;
}
public Integer getIdProvincia() {
return idProvincia;
}
public void setIdProvincia(Integer idProvincia) {
this.idProvincia = idProvincia;
}
public String getDescricaoProv() {
return descricaoProv;
}
public void setDescricaoProv(String descricaoProv) {
this.descricaoProv = descricaoProv;
}
}
É o que imaginei mesmo. Quando a lista é retornada e serializada para JSON, entra em loop, pq o municipio possui um bairro, e o bairro possui um municipio, e o municipio possui um bairro, … , etc. Sacou?
Vc pode usar uma classe para retornar os dados do municipio, veja:
MunicipioResource.java
public class MunicipioResource {
private final Long id;
private final String nome;
public MunicipioResource(Municipio municipio) {
this.id = municipio.getId();
this.nome = municipio.getNome();
}
// crie apenas os gets, não precisa de ter sets aqui
}
E no endpoint, use o map
:
return municipioService.listaMuniPorProv(idProvincia)
.stream()
.map(m -> new MunicipioResource(m))
.collect(Collectors.toList());
Dessa forma, o json retornado será assim:
[{
"id": 1,
"nome": "M1"
}, {
"id": 2,
"nome": "M2"
}, {
"id": 3,
"nome": "M3"
}]
Entendeu?
Particularmente, gosto de usar o sufixo *Resource para essas classes, pq representa bem o que o endpoint retorna, que são recursos dos servidor.
Vou tentar Lucas!
Muito obrigado a todos, com a última explicação do Lucas consegui resolver o problema.