How to remove _class from spring data mongo collection - Image

How to remove _class from spring data mongo collection

Spring Framework

Don’t want that extra _class key on all your records, read on!…

When using spring data mongo it by default adds a _class key to your collection to be able to handle inheritance.

But if your domain model is simple and flat, you can remove it by overriding the default MappingMongoConverter

import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.MongoDbFactory;
import org.springframework.data.mongodb.core.convert.*;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext;

@Configuration
public class MongoConfig {

    @Bean
    public MappingMongoConverter mappingMongoConverter(MongoDbFactory factory, MongoMappingContext context, BeanFactory beanFactory) {
        DbRefResolver dbRefResolver = new DefaultDbRefResolver(factory);
        MappingMongoConverter mappingConverter = new MappingMongoConverter(dbRefResolver, context);
        try {
            mappingConverter.setCustomConversions(beanFactory.getBean(CustomConversions.class));
        }
        catch (NoSuchBeanDefinitionException ignore) {}

        // Don't save _class to mongo
        mappingConverter.setTypeMapper(new DefaultMongoTypeMapper(null));

        return mappingConverter;
    }

}
Create test data with spring data mongo - Image

Create test data with spring data mongo

Spring Framework

When developing applications you often need some data when you start out, and it’s always a problem getting it into the application, should you use the domain model to programatically create all the records, should you dump the data directly into the database?

The following demo does it by using Jackson2RepositoryPopulatorFactoryBean

How?

place .json files in src/main/resources/mock-data, they don’t have to be named anything special. Just make sure that the get loaded in the correct order, so that the entities that you are trying to link to with @DbRef exists.

References?

Only the root objects need to have the special _class key, so that jackson knows where to start.

So if you have a embedded object include it as usual

[
  {
    "_class": "se.radley.demo.user.User",
    "id": "leon",
    "email": "leon@radley.se",
    "firstName": "Leon",
    "lastName": "Radley",
    "address": {
      "street": "my street",
      "city": "my city"
    }
  }
]

If you need to link to another document via @DbRef the other document needs to have a constructor or factory method to be able to create the document

/**
 * Factory constructor for creating DbRefs
 * @param id
 */
private User(String id) {
    this.id = id;
}

public static User ref(String id) {
    return new User(id);
}

That way you can easily create references to objects without having to get the from the db with

User leon = User.ref("leon");
Angular App in Sub Path using base - Image

Angular App in Sub Path using base

Angular

When integrating angular into a system that isn’t new it’s a bit of a struggle trying to get all routes to work and get the initial data in there.

At work we have recently started to integrate Angular with our current applications by serving them up from a sub path, such as: http://myapp.com/admin/survey/123

The problem I faced with this was that I didn’t want to have to include /admin/survey/123 in all my routes / links. There must be a better way.

Meet the html base tag

It’s not one of the most used html tags but it’s great. By adding:

<base href="/admin/survey/123/" />

to the top of your <head> all relative links now are relative to the specified base href.

So a link that would have looked like this html <a href="/admin/survey//field/"></a> can now be shortened to html <a href="./field/"></a>

Notice the period (.) before the / this is what makes it relative to the base tag and not the the domain.

And the same goes for all the routes. Something that would before look like this:

var prefix = '/admin/survey/123/';

.config(function ($routeProvider, $locationProvider) {
	$locationProvider.html5Mode(true);

	routeProvider
	.when(prefix, {
		templateUrl: prefix + 'partial.html',
		controller: 'PartialCtrl'
	})
	.when(prefix + 'index', {
		templateUrl: prefix + 'partial.html',
		controller: 'PartialCtrl'
	})
});

Could now be simplified as this.

.config(function ($routeProvider, $locationProvider) {
	$locationProvider.html5Mode(true);

	$routeProvider
	.when('/', {
		templateUrl: 'partial.html',
		controller: 'PartialCtrl'
	})
	.when('/index', {
		templateUrl: 'partial.html',
		controller: 'PartialCtrl'
	})
	.otherwise({
		redirectTo: '/'
	});
});

Base href data

You may ask but how would I get hold of the survey.id or any other survey data.

By creating an Angular constant with the surveyId we can then inject where ever we want.

<script>
	// The @survey variable is coming from play via @(survey: Survey)
	angular.module('app').constant('surveyId', '@survey.id');
</script>

We can then add a main app controller and survey service that loads the survey data as json from /api/admin/survey/123 and injects it into the $rootScope

<!doctype html>
<html ng-app="app" ng-controller="AppCtrl">
<head>
	<!-- again we are using play's variable, but it could be from any backend... -->
	<base href="/admin/survey/@survey.id/" />
	...
</head>
<body>
	...
<body>
</html>

And then the AppCtrl and SurveyService

// in SurveyService.js
angular.module('app').factory('SurveyService', function ($resource) {
	return $resource('/api/admin/survey/:surveyId', {surveyId: '@id'});
});

// in AppCtrl.js
angular.module('app').controller('AppCtrl', function ($scope, $rootScope, SurveyService, surveyId) {
	// Notice how we injected the surveyId constant and SurveyService

	$rootScope.survey = SurveyService.get({surveyId: surveyId});
});

Conclusion

By being able to have angular apps live under a sub path and not be bound to that specific path makes your life a lot simpler when you want to use that same app in another project.