NoSQL MongoDB - Can't serialize class br.com.ucsal.monografia.model.TwitterModel

Pessoal estou tendo problemas para persistir uma classe News no MongoDB e recebendo o seguinte erro logo abaixo.
Segue todas as classes pertinentes.

Desde já agradeço a colaboração.

package br.com.ucsal.monografia.controller;

import java.util.List;

import br.com.ucsal.monografia.model.HashTag;
import br.com.ucsal.monografia.model.News;
import br.com.ucsal.monografia.service.HashTagService;
import br.com.ucsal.monografia.service.NewsService;
import br.com.ucsal.monografia.twitter.TwitterLoader;

public class CargaNews {
	
	private static void save(List<News> newss) {
		
		NewsService newsService = new NewsService();
		
		for (News news : newss) {
			newsService.save(news);			
		}
		
	}

}
package br.com.ucsal.monografia.service;

import java.util.List;
import java.util.Map;

import br.com.caelum.vraptor.ioc.Component;
import br.com.ucsal.monografia.dao.NewsDao;
import br.com.ucsal.monografia.model.News;

@Component
public class NewsService {
	
	private NewsDao dao = new NewsDao();
	
	public void save(News news) {
		dao.save(news);
	}

}
package br.com.ucsal.monografia.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import br.com.ucsal.monografia.converter.NewsConverter;
import br.com.ucsal.monografia.model.News;

import com.mongodb.DBObject;

public class NewsDao extends EntityDao<News> {

	public NewsDao() {
		super(News.class);
	}

	public void save(News news) {
		Map<String, Object> mapNews = new NewsConverter().converterToMap(news);
		save(mapNews);
	}

}
package br.com.ucsal.monografia.converter;

import java.util.HashMap;
import java.util.Map;
import br.com.ucsal.monografia.model.Feed;
import br.com.ucsal.monografia.model.News;
import br.com.ucsal.monografia.model.NewsType;
import br.com.ucsal.monografia.model.TwitterModel;

import com.mongodb.DBObject;

public class NewsConverter {

	public Map<String, Object> converterToMap(News news) {
		Map<String, Object> mapNews = new HashMap<String, Object>();
		mapNews.put("twitterModel", news.getTwitterModel());
		mapNews.put("feed", news.getFeed());
		mapNews.put("newsType", news.getNewsType());

		return mapNews;
	}

}
package br.com.ucsal.monografia.model;

import java.io.Serializable;

public class TwitterModel implements Serializable{
	
	private static final long	serialVersionUID	= 7686683331955611044L;
	
	private String twitt;

	public TwitterModel() {
	}
	
	public String getTwitt() {
		return twitt;
	}

	public void setTwitt(String twitt) {
		this.twitt = twitt;
	}

} 
package br.com.ucsal.monografia.model;

import java.io.Serializable;

public class News implements Serializable{
	
	private static final long	serialVersionUID	= 7686683331955611044L;

    private String id;
	private TwitterModel twitterModel;
	private Feed feed;		
	private NewsType newsType;

	public News(TwitterModel twitterModel, Feed feed, NewsType newsType) {
		this.twitterModel = twitterModel;
		this.feed = feed;		
		this.newsType = newsType;
	}
	
	public News() {
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public TwitterModel getTwitterModel() {
		return twitterModel;
	}

	public TwitterModel getTwitter() {
		return twitterModel;
	}

	public void setTwitterModel(TwitterModel twitterModel) {
		this.twitterModel = twitterModel;
	}

	public Feed getFeed() {
		return feed;
	}

	public void setFeed(Feed feed) {
		this.feed = feed;
	}

	public NewsType getNewsType() {
		return newsType;
	}

	public void setNewsType(NewsType newsType) {
		this.newsType = newsType;
	}
	
} 
Exception in thread "main" java.lang.IllegalArgumentException: can't serialize class br.com.ucsal.monografia.model.TwitterModel
	at org.bson.BSONEncoder._putObjectField(BSONEncoder.java:188)
	at org.bson.BSONEncoder.putObject(BSONEncoder.java:119)
	at org.bson.BSONEncoder.putObject(BSONEncoder.java:65)
	at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:131)
	at com.mongodb.DBApiLayer$MyCollection.insert(DBApiLayer.java:97)
	at com.mongodb.DBCollection.insert(DBCollection.java:75)
	at com.mongodb.DBCollection.save(DBCollection.java:545)
	at com.mongodb.DBCollection.save(DBCollection.java:523)
	at br.com.ucsal.monografia.dao.EntityDao.save(EntityDao.java:39)
	at br.com.ucsal.monografia.dao.NewsDao.save(NewsDao.java:20)
	at br.com.ucsal.monografia.service.NewsService.save(NewsService.java:16)
	at br.com.ucsal.monografia.controller.CargaNews.save(CargaNews.java:32)
	at br.com.ucsal.monografia.controller.CargaNews.main(CargaNews.java:23)

Cara post seu EntityDao.
Pelo que vi acredito que você esta usando a API pura do MongoDB certo?

Na sua classe NewsConverter o seu método converterToMap devolve um Map faça o mesmo retorna um DBObject.

public Map<String, Object> converterToMap(News news) {  
        Map<String, Object> mapNews = new HashMap<String, Object>();  
        mapNews.put("twitterModel", news.getTwitterModel());  
        mapNews.put("feed", news.getFeed());  
        mapNews.put("newsType", news.getNewsType());  
  
        return mapNews;  
    } 

para

public DBObject converterToMap(News news) {  
        DBObject news = new BasicDBObject();
        news.put("twitterModel", news.getTwitterModel());
        news.put("feed", news.getFeed());
        news.put("newsType", news.getNewsType());
        return news;  
    } 

Só mais uma dica, na sua classe News troque seu id de String pra ObjectId

private String id; 

para

private ObjectId id; 

Boa noite jweibe,

Cara obrigado pela dica mas não acredito que resolveria pois de acordo com a classe EntityDao o método save já faz esta conversão do map para BasicDBObject antes de salvar na coleção conforme abaixo:

Vou tentar alterar o id da classe News de String para ObjectId como vc sugeriu e ver no que dá.

Teve um rapaz no grupos NoSQL que sugeriu alterar mapNews.put(“twitterModel.twitt”, news.getTwitterModel().getTwitt());
pois o atributo twitterModel não é primitivo.
https://groups.google.com/forum/?hl=pt-BR&fromgroups=#!topic/nosqlbr/K9WUOxQ1x9k

Teve outro rapaz no grupos MongoDB que informou que só era possível persistir objetos contendo atributos que também são objetos e não primitivos usando frameworks como Morphia or Spring Data MongoDB, caso contrário preciso fazer o parse manual como nesta converter sempre mantendo a instancia do BasicDBObject antes das operações de acesso ao MongoDB.
https://groups.google.com/forum/?fromgroups=#!topic/mongodb-user/fpwhuFX8C14

Vou tentar seguir a idéia de pegar o news.getTwitterModel().getTwitt() pois atende meu propósito no momento.

Segue abaixo a classe EntityDao que estou usando no momento.


package br.com.ucsal.monografia.dao;

import com.mongodb.BasicDBObject;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class EntityDao<T> implements IDao {

	private Class<T> persistentClass;
	private DBCollection dbCollection;

	public EntityDao(Class<T> persistentClass) {
		this.persistentClass = persistentClass;
		this.dbCollection =	MongoConnection.getInstance().getDB().getCollection(persistentClass.getSimpleName());
	}

	protected Class<T> getPersistentClass() {
		return persistentClass;
	}

	protected void setPersistentClass(Class<T> persistentClass) {
		this.persistentClass = persistentClass;
	}

	protected void setDbCollection(DBCollection dbCollection) {
		this.dbCollection = dbCollection;
	}

	protected DBCollection getDbCollection() {
		return dbCollection;
	}

	public void save(Map<String, Object> mapEntity) {
		BasicDBObject document = new BasicDBObject(mapEntity);
		dbCollection.save(document);
		System.out.println("Saved: " + document);
	}

	public void update(Map<String, Object> mapQuery, Map<String, Object> mapEntity) {
		BasicDBObject query = new BasicDBObject(mapQuery);
		BasicDBObject entity = new BasicDBObject(mapEntity);
		dbCollection.update(query, entity);
	}

	public void delete(Map<String, Object> mapEntity) {
		BasicDBObject entity = new BasicDBObject(mapEntity);
		dbCollection.remove(entity);
	}

	public DBObject findOne(Map<String, Object> mapEntity) {
		BasicDBObject query = new BasicDBObject(mapEntity);
		return dbCollection.findOne(query);
	}

	public List<DBObject> findAll() {
		List<DBObject> list = new ArrayList<DBObject>();
		DBCursor cursor = dbCollection.find();
		while (cursor.hasNext()) {
			list.add(cursor.next());
		}
		return list;
	}

	public List<DBObject> findKeyValue(Map<String, Object> keyValue) {
		List<DBObject> list = new ArrayList<DBObject>();
		DBCursor cursor = dbCollection.find(new BasicDBObject(keyValue));
		while (cursor.hasNext()) {
			list.add(cursor.next());
		}
		return list;
	}

}

Cara já utilizo o MongoDB a algum tempo e nunca tive problemas com isso.

jweibe, valeu pela dica.

Fiz a alteração na converter como a seguir e funcionou perfeitamente, precisei modificar em cada parâmetro relevante para a aplicação pegando o atributo internos de cada classe e persistindo no MongoDB. No momento atendeu para o que eu preciso.

Obrigado pela colaboração, qualquer coisa volto a entrar em contato.

public Map<String, Object> converterToMap(News news) {    
        Map<String, Object> mapNews = new HashMap<String, Object>();    
        mapNews.put("twitterModel.twitt", news.getTwitterModel().getTwitt());   
        //mapNews.put("feed", news.getFeed());    
        //mapNews.put("newsType", news.getNewsType());    
    
        return mapNews;    
}   

Cara mais um dica da uma olhada no Morphia, ele abstrai muita coisa da API nativa!

Blz, valeu pela dica, vou dar uma olhada no Morphia mesmo, também não quero re-inventar a roda… hehehehe

Grande abraço.

[quote=gscoelho]Blz, valeu pela dica, vou dar uma olhada no Morphia mesmo, também não quero re-inventar a roda… hehehehe

Grande abraço.[/quote]

Cara para o intuito do seu projeto acho mais sensato utilizar Morphia por conta das abstrações que ele faz, porém a utilização da API
nativa do Mongo acho melhor por ter um controle sobre o banco, detalhes como os $ref que o Morphia cria que faz uma analogia as
foreign key dos bancos relacionais pode ter um custo na performance do seu banco, quando se tem um fluxo muito grande de dados.
Por fim da uma lida no DOC do Mongo no site, que tu vai aprender coisas bem legais sobre.