Problemas na geração do arquivo xml com Java?

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 </>)

1 curtida

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);
      }
    });
  });
});
1 curtida

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)
1 curtida

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;
	}

}

1 curtida

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 Bairros. Se na Provincia tiver uma lista de Municipios, ou na entidade Bairro tiver um Municipio, a serialização vai ficar em loop e dá erro.

1 curtida
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;
	}

}

1 curtida

É 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.

1 curtida

Vou tentar Lucas!

Muito obrigado a todos, com a última explicação do Lucas consegui resolver o problema.

2 curtidas