I've been trying for about an hour now to register a codec I made for one of my classes in a game I am working on. The class is called Item
. I tried the code and suggestions from these 3 places:
and here is the code I cam up with:
CodecRegistry defaultCodecRegistry = MongoClient.getDefaultCodecRegistry();
MyCodecProvider myCodecProvider = new MyCodecProvider();
ItemCodec itemCodec = new ItemCodec(defaultCodecRegistry);
CodecRegistry codecRegistry = CodecRegistries.fromRegistries(CodecRegistries.fromCodecs(itemCodec), CodecRegistries.fromProviders(myCodecProvider), defaultCodecRegistry);;
MongoClientOptions options = MongoClientOptions.builder().codecRegistry(codecRegistry).build();
client = new MongoClient("localhost:27017", options);
So I built a Codec and codec provider called MyCodecProvider
, so what am I doing wrong, how can this be so complicated? Am I missing something? It seems more complicated than it needs to be. If you need more code please ask. Thanks.
Edit: The exact error I get is org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for class [Lnet.hollowbit.archipeloserver.items.Item;.
Also, I am trying to parse an Item array, do I need to make a codec specifically for the array too?
You can do Mongo codecs for arrays using ArrayList as follows:
This is the class representing an Order. It includes an ArrayList of items.
package com.example.model;
import java.util.ArrayList;
import org.bson.types.ObjectId;
/**
* Class representing an Order.
*/
public class Order
{
private ObjectId id;
private ArrayList<Item> items;
/**
* Default constructor. Needed for testing.
*/
public Order() {
this.items = new ArrayList<>();
}
/**
* Sets the id of the Order.
* @param id The new id of the Order.
*/
public void setId(ObjectId id) {
this.id = id;
}
/**
* Gets the id of the Order.
* @return The id of the Order.
*/
public ObjectId getId() {
return this.id;
}
/**
* Sets the items for the Order.
* @param items The items for the Order.
*/
public void setItems(ArrayList<Item> items) {
this.items = items;
}
/**
* Gets the items for the Order.
* @return The items for the Order.
*/
public ArrayList<Item> getItems() {
return items;
}
/**
* Adds an item to the Order.
* @param item The new Item to add to the Order.
*/
public void addItem(Item item) {
this.items.add(item);
}
}
This is the class representing an Order Item. There can be any number of items that are a part of an order. Items are embedded within the Order document in Mongo.
package com.example.model;
import org.bson.types.ObjectId;
/**
* Class representing an order item.
*/
public class Item
{
private ObjectId id;
private String name;
/**
* Constructor.
*/
public Item() {
//
}
/**
* Sets the id of the Item.
* @param id The new id of the Item.
*/
public void setId(ObjectId id) {
this.id = id;
}
/**
* Gets the id of the Item.
* @return The id of the Item.
*/
public ObjectId getId() {
return this.id;
}
/**
* Sets the name of the Item.
* @param name The new name of the Item.
*/
public void setName(String name) {
this.name = name;
}
/**
* Gets the name of the Item.
* @return The name of the Item.
*/
public String getName() {
return this.name;
}
}
Simple converter class that converts Items to/from Documents.
package com.example.mongo;
import com.example.model.Item;
import org.bson.Document;
/**
* Converts Mongo Documents to/from Items.
*/
public class ItemConverter {
/**
* Convert the passed Item into a Mongo Document.
* @param item The Item that you want to convert into a Mongo Document.
* @return Returns the Document that was created from the passed Item.
*/
public Document convert(Item item) {
Document document = new Document();
document.put("_id", item.getId());
document.put("name", item.getName());
return document;
}
/**
* Convert the passed Mongo Document into an Item.
* @param document The Document that you want to convert into an Item.
* @return Returns the Item that was created from the passed Mongo Document.
*/
public Item convert(Document document) {
Item item = new Item();
item.setId(document.getObjectId("_id"));
item.setName(document.getString("name"));
return item;
}
}
Codec for encoding and decoding Items.
package com.example.mongo;
import com.example.model.Item;
import com.mongodb.MongoClient;
import org.bson.BsonReader;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.bson.BsonWriter;
import org.bson.Document;
import org.bson.codecs.Codec;
import org.bson.codecs.CollectibleCodec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.types.ObjectId;
/**
* Mongo Decoder for Items.
*/
public class ItemCodec implements CollectibleCodec<Item> {
private final CodecRegistry registry;
private final Codec<Document> documentCodec;
private final ItemConverter converter;
/**
* Default constructor.
*/
public ItemCodec() {
this.registry = MongoClient.getDefaultCodecRegistry();
this.documentCodec = this.registry.get(Document.class);
this.converter = new ItemConverter();
}
/**
* Codec constructor.
* @param codec The existing codec to use.
*/
public ItemCodec(Codec<Document> codec) {
this.documentCodec = codec;
this.registry = MongoClient.getDefaultCodecRegistry();
this.converter = new ItemConverter();
}
/**
* Registry constructor.
* @param registry The CodecRegistry to use.
*/
public ItemCodec(CodecRegistry registry) {
this.registry = registry;
this.documentCodec = this.registry.get(Document.class);
this.converter = new ItemConverter();
}
/**
* Encode the passed Item into a Mongo/BSON document.
* @param writer The writer to use for encoding.
* @param item The Item to encode.
* @param encoderContext The EncoderContext to use for encoding.
*/
@Override
public void encode(
BsonWriter writer,
Item item,
EncoderContext encoderContext
) {
Document document = this.converter.convert(item);
documentCodec.encode(writer, document, encoderContext);
}
/**
* Get the class that this Codec works with.
* @return Returns the class that this Codec works with.
*/
@Override
public Class<Item> getEncoderClass() {
return Item.class;
}
/**
* Decodes a Mongo/BSON document into an Item.
* @param reader The reader containing the Document.
* @param decoderContext The DecoderContext to use for decoding.
* @return Returns the decoded Item.
*/
@Override
public Item decode(BsonReader reader, DecoderContext decoderContext) {
Document document = documentCodec.decode(reader, decoderContext);
Item item = this.converter.convert(document);
return item;
}
/**
* Generates a new ObjectId for the passed Item (if absent).
* @param item The Item to work with.
* @return Returns the passed Item with a new id added if there
* was none.
*/
@Override
public Item generateIdIfAbsentFromDocument(Item item) {
if (!documentHasId(item)) {
item.setId(new ObjectId());
}
return item;
}
/**
* Returns whether or not the passed Item has an id.
* @param Item The Item that you want to check for
* the presence of an id.
* @return Returns whether or not the passed Item has an id.
*/
@Override
public boolean documentHasId(Item Item) {
return (Item.getName() != null);
}
/**
* Gets the id of the passed Item. If there is no id, it will
* throw an IllegalStateException (RuntimeException).
* @param Item The Item whose id you want to get.
* @return Returns the id of the passed Item as a BsonValue.
*/
@Override
public BsonValue getDocumentId(Item Item)
{
if (!documentHasId(Item)) {
throw new IllegalStateException("The document does not contain an _id");
}
return new BsonString(Item.getName());
}
}
Codec for encoding/decoding Orders.
package com.example.mongo;
import com.example.model.Item;
import com.example.model.Order;
import com.mongodb.MongoClient;
import java.util.ArrayList;
import org.bson.BsonReader;
import org.bson.BsonString;
import org.bson.BsonValue;
import org.bson.BsonWriter;
import org.bson.Document;
import org.bson.codecs.Codec;
import org.bson.codecs.CollectibleCodec;
import org.bson.codecs.DecoderContext;
import org.bson.codecs.EncoderContext;
import org.bson.codecs.configuration.CodecRegistry;
import org.bson.types.ObjectId;
/**
* Mongo decoder for Orders.
*/
public class OrderCodec implements CollectibleCodec<Order> {
private final CodecRegistry registry;
private final Codec<Document> documentCodec;
private final ItemConverter itemConverter;
/**
* Default constructor.
*/
public OrderCodec() {
this.registry = MongoClient.getDefaultCodecRegistry();
this.documentCodec = this.registry.get(Document.class);
this.itemConverter = new ItemConverter();
}
/**
* Codec constructor.
* @param codec The existing codec to use.
*/
public OrderCodec(Codec<Document> codec) {
this.registry = MongoClient.getDefaultCodecRegistry();
this.documentCodec = codec;
this.itemConverter = new ItemConverter();
}
/**
* Registry constructor.
* @param registry The CodecRegistry to use.
*/
public OrderCodec(CodecRegistry registry) {
this.registry = registry;
this.documentCodec = this.registry.get(Document.class);
this.itemConverter = new ItemConverter();
}
/**
* Encode the passed Order into a Mongo/BSON document.
* @param writer The writer to use for encoding.
* @param order The Order to encode.
* @param encoderContext The EncoderContext to use for encoding.
*/
@Override
public void encode(
BsonWriter writer,
Order order,
EncoderContext encoderContext
) {
Document document = new Document();
document.put("_id", order.getId());
document.put("items", order.getItems());
documentCodec.encode(writer, document, encoderContext);
}
/**
* Get the class that this Codec works with.
* @return Returns the class that this Codec works with.
*/
@Override
public Class<Order> getEncoderClass() {
return Order.class;
}
/**
* Decodes a Mongo/BSON document into an Order.
* @param reader The reader containing the Document.
* @param decoderContext The DecoderContext to use for decoding.
* @return Returns the decoded Order.
*/
@Override
public Order decode(BsonReader reader, DecoderContext decoderContext) {
Document document = documentCodec.decode(reader, decoderContext);
Order order = new Order();
order.setId(document.getObjectId("_id"));
ArrayList<Document> docArr = (ArrayList) document.get("items");
for (Document doc : docArr) {
Item item = this.itemConverter.convert(doc);
order.addItem(item);
}
return order;
}
/**
* Generates a new ObjectId for the passed Order (if absent).
* @param order The Order to work with.
* @return Returns the passed Order with a new id added if there
* was none.
*/
@Override
public Order generateIdIfAbsentFromDocument(Order order) {
if (!documentHasId(order)) {
order.setId(new ObjectId());
}
return order;
}
/**
* Returns whether or not the passed Order has an id.
* @param order The Order that you want to check for
* the presence of an id.
* @return Returns whether or not the passed Order has an id.
*/
@Override
public boolean documentHasId(Order order) {
return (order.getId() != null);
}
/**
* Gets the id of the passed Order. If there is no id, it will
* throw an IllegalStateException (RuntimeException).
* @param order The Order whose id you want to get.
* @return Returns the id of the passed Order as a BsonValue.
*/
@Override
public BsonValue getDocumentId(Order order) {
if (!documentHasId(order)) {
throw new IllegalStateException("The document does not contain an _id");
}
return new BsonString(order.getId().toHexString());
}
}
Main class for the app. Here we register the codecs and create our MongoClient.
package com.example.main;
import com.example.model.Item;
import com.example.model.Order;
import com.example.mongo.ItemCodec;
import com.example.mongo.OrderCodec;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.ServerAddress;
import org.bson.Document;
import org.bson.codecs.Codec;
import org.bson.codecs.configuration.CodecRegistries;
import org.bson.codecs.configuration.CodecRegistry;
/**
* Main class.
*/
public class Main {
/**
* Main function for the app.
* @param args the command line arguments
*/
public static void main(String[] args) {
CodecRegistry codecRegistry = MongoClient.getDefaultCodecRegistry();
Codec<Document> documentCodec = codecRegistry.get(Document.class);
Codec<Item> itemCodec = new ItemCodec(codecRegistry);
Codec<Order> orderCodec = new OrderCodec(codecRegistry);
codecRegistry = CodecRegistries.fromRegistries(
MongoClient.getDefaultCodecRegistry(),
CodecRegistries.fromCodecs(
documentCodec,
itemCodec,
orderCodec
)
);
MongoClientOptions options = MongoClientOptions.builder().codecRegistry(codecRegistry).build();
MongoClient mongo = new MongoClient(new ServerAddress("localhost", 27018), options);
// Your code here.
}
}
From there you can read/write orders and items to/from Mongo.