Skip to content

Getting Started

João Sousa edited this page Oct 3, 2017 · 5 revisions

Welcome to the Getting Started page!

First things first!

Check out the Prerequisites page, which gives you a glimpse of the few things you need to use Smof.

Add the project to your classpath and let's get started.

Smof

This framework uses an object to perform all the main operations, in order to make it simple and straightforward. So, after starting a mongo server and copying the project to the classpath, use Smof to create a connection to the mongo server:

import org.smof.collection.Smof;

...
...

final Smof smof = Smof.create("localhost", 27017, "myDB");

Now, with this connection you can load and create collections, insert, update or query elements.

Load collections

The main goal of this project is to (automatically) turn java objects in BSON documents, stored by mongoDB. To achieve this goal efficiently, but still give the user some control over the serialized data, all java object that are to be serialized to BSON documents must have some specifications.

To load a collection in smof:

import org.smof.collection.Smof;

public static void main(String[] args) {
		//create the smof object with host, port and database name
		final Smof smof = Smof.create("localhost", 27017, "myDB");
		//loads a collection and map it to a type
		smof.loadCollection("bottles", Bottle.class);
		//always close the connection
		smof.close();
}

Can i map a collection to any java type?

  • Short answer: No, only types that implement the Element type.
  • Long answer: Keep reading :)

Element

All java objects that are to be mapped to a mongo collection must have some special properties (e.g. the _id property). However, all this "special properties" are already taken care by the Element class.

Let's talk practical then. For instance, consider this simple Bottle class:

public static class Bottle {

	private String liquid;
	private double amount;
	private double capacity;

	public Bottle(String liquid, double capacity) {
		this(liquid, capacity, 0.0);
	}

	public boolean isFull() {
		return capacity == amount;
	}

	public double fill(Double amount) {
		final double left = capacity-amount;
		if(left < amount) {
			this.amount = capacity;
			return amount-left;
		}
		this.amount += amount;
		return left-amount;
	}
}

In order to map it to a fully functional mongoDB, this object must extend AbstractElement (an abstract implementation of Element). But that's not all. Bottle has 3 fields, but you might not want to store all of them. You might also want to stored them in specific formats (e.g. for cross-platform support). So, each field must specify its name and type in the database (but only for the fields you want to store):

public static class Bottle extends AbstractElement {

	private static final String CAPACITY = "capacity";
	private static final String AMOUNT = "liquid_amount";
	private static final String LIQUID = "liquid";

	@SmofString(name = LIQUID)
	private String liquid;

	@SmofNumber(name = AMOUNT)
	private double amount;

	@SmofNumber(name = CAPACITY)
	private double capacity;

	public Bottle(String liquid, double capacity) {
		this(liquid, capacity, 0.0);
	}

	public boolean isFull() {
		return capacity == amount;
	}

	public double fill(Double amount) {
		final double left = capacity-amount;
		if(left < amount) {
			this.amount = capacity;
			return amount-left;
		}
		this.amount += amount;
		return left-amount;
	}
}

This specification is made through Java Annotations. The basic smofTypes are:

  • @SmofString - a general purpose string;
  • @SmofNumber- a BsonNumber. Assumes different Bson types, according to the field's java type;
  • @SmofDate - Used for dates. Supports Java 8 Time and Java Date (natively supported by the MongoDB Java Driver);
  • @SmofByte - Useful for byte arrays;
  • @SmofBoolean - Useful for booleans;
  • @SmofArray - Maps java collections to BSONArrays. The API only supports java collections at the moment.
  • @SmofObject - Useful for user-created java objects. All types used in one or more fields tagged with this SmofType must specify the minimal required smof properties. This tag is also used for referencing other objects (see referencing);
  • @SmofObjectId - Used to store direct ObjectId references.

Write Operations

Write operations can be divided in two main areas: Inserts and updates.

Inserts

An insert is quite straightforward. All you need is to create a Smof instance, load or create the collection you want to map to the correspondent type and finally, use the Smof instance to insert the desired element:

import org.smof.collection.Smof;

public static void main(String[] args) {
		//create the smof object with host, port and database name
		final Smof smof = Smof.create("localhost", 27017, "myDB");
		//create a new bottle
		final Bottle bottle = new Bottle("water", 1.0);
		//loads a collection and map it to a type
		smof.loadCollection("bottles", Bottle.class);
		//saves the bottle
		smof.insert(bottle);
		//always close the connection
		smof.close();
}

As i said, quite straightforward. Note: In smof, an insert is basically a replace with upsert. This prevents the mongodbdriver from throwing an exception when an element that already exists is added to the collection.

Updates

Updates are a bit more complex than inserts. These operations can be divided in two groups: replace operations (i.e. state-based operations) and update (i.e. op-based operations). As smof is an ORM, where the object(s) you're working on is always in memory, the full state of such object is always present, thus replaces are the recommended operations. In other words, you read the object from the database, update such object and then issue a replace on the database two fully replace the outdated object by its most updated version:

//...
//...
		//fill the bottle
		bottle.fill(0.5);
		//update the object on the database
		smof.update(Bottle.class).fromElement(bottle);

Actually, this is indeed quite easy-to-use. This whole process is so smooth because Smof assumes that bottle is already in the database (i.e. has an already-existent _id), thus it simply searches for the element's id and replaces the first result by the object passed in the fromElement method (note: as all MongoDB collections have a unique index on the _id property, the 'first result' in this query will actually (always) be the only result, so you can trust the database will find the right object).

Table of Contents

Clone this wiki locally