Java tutorial
/** * Axelor Business Solutions * * Copyright (C) 2005-2016 Axelor (<http://axelor.com>). * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.axelor.db; import java.io.InputStream; import java.util.Date; import java.util.Map; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.joda.time.LocalDate; import org.joda.time.LocalDateTime; import org.yaml.snakeyaml.TypeDescription; import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.constructor.Construct; import org.yaml.snakeyaml.constructor.Constructor; import org.yaml.snakeyaml.nodes.Node; import org.yaml.snakeyaml.nodes.NodeId; import org.yaml.snakeyaml.nodes.Tag; import com.axelor.common.ClassUtils; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.inject.persist.Transactional; /** * This class can be used to load test data for JPA entities. * * <p> * It processes YAML files located in {@code /fixtures}. * * <p> * For example, the following schema: * * <pre> * * @Entity * @Table(name = "CONTACT_CIRCLE") * public class Circle extends Model { * private String code; * private String name; * ... * ... * } * * @Entity * @Table(name = "CONTACT_CONTACT") * public class Contact extends Model { * private String firstName; * private String lastName; * private String email; * * @ManyToMany * private Set<Circle> circles; * ... * ... * ... * </pre> * * The fixtures should be defined like this: * * <pre> * - !Circle: &family * code: family * name: Family * * - !Circle: &friends * code: friends * name: Friends * * - !Circle: &business * code: business * name: Business * * - !Contact: * firstName: John * lastName: Smith * email: j.smith@gmail.com * circles: * - *friends * - *business * * - !Contact: * firstName: Tin * lastName: Tin * email: tin.tin@gmail.com * circles: * - *business * </pre> * * <p> * In order to use the fixture data, the {@link JpaFixture} must be injected. * * <pre> * @RunWith(GuiceRunner.class) * @GuiceModules({MyModule.class}) * class FixtureTest { * * @Inject * private JpaFixture fixture; * * @Before * public void setUp() { * fixture.load("demo-data.yml"); * fixture.load("demo-data-extra.yml"); * } * * @Test * public void testCount() { * Assert.assertEqual(2, Contact.all().count()); * ... * } * ... * } * </pre> */ public class JpaFixture { private InputStream read(String resource) { return ClassUtils.getResourceStream("fixtures/" + resource); } @Transactional public void load(String fixture) { final InputStream stream = read(fixture); final Map<Node, Object> objects = Maps.newLinkedHashMap(); if (stream == null) { throw new IllegalArgumentException("No such fixture found: " + fixture); } final Constructor ctor = new Constructor() { { yamlClassConstructors.put(NodeId.scalar, new TimeStampConstruct()); } class TimeStampConstruct extends Constructor.ConstructScalar { Construct dateConstructor = yamlConstructors.get(Tag.TIMESTAMP); @Override public Object construct(Node nnode) { if (nnode.getTag().equals(Tag.TIMESTAMP)) { Date date = (Date) dateConstructor.construct(nnode); if (nnode.getType() == LocalDate.class) { return new LocalDate(date, DateTimeZone.UTC); } if (nnode.getType() == LocalDateTime.class) { return new LocalDateTime(date, DateTimeZone.UTC); } return new DateTime(date, DateTimeZone.UTC); } else { return super.construct(nnode); } } } @Override protected Object constructObject(Node node) { Object obj = super.constructObject(node); if (objects.containsKey(node)) { return objects.get(node); } if (obj instanceof Model) { objects.put(node, obj); return obj; } return obj; } }; for (Class<?> klass : JPA.models()) { ctor.addTypeDescription(new TypeDescription(klass, "!" + klass.getSimpleName() + ":")); } Yaml data = new Yaml(ctor); data.load(stream); for (Object item : Lists.reverse(Lists.newArrayList(objects.values()))) { try { JPA.manage((Model) item); } catch (Exception e) { } } } }