diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..129c104
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,76 @@
+.idea
+*.iml
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+### Eclipse template
+
+.metadata
+bin/
+tmp/
+*.tmp
+*.bak
+*.swp
+*~.nib
+local.properties
+.settings/
+.loadpath
+.recommenders
+
+# Eclipse Core
+.project
+
+# External tool builders
+.externalToolBuilders/
+
+# Locally stored "Eclipse launch configurations"
+*.launch
+
+# PyDev specific (Python IDE for Eclipse)
+*.pydevproject
+
+# CDT-specific (C/C++ Development Tooling)
+.cproject
+
+# JDT-specific (Eclipse Java Development Tools)
+.classpath
+
+# Java annotation processor (APT)
+.factorypath
+
+# Tern plugin
+.tern-project
+
+# TeXlipse plugin
+.texlipse
+
+# STS (Spring Tool Suite)
+.springBeans
+
+# Code Recommenders
+.recommenders/
+### JetBrains template
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff:
+.idea/
+## File-based project format:
+*.iws
+
+### Maven template
+target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+
+src/profiles/development
+src/profiles/production
+Будет удалено checks/
+Будет удалено src/test/jetty/
+Будет удалено src/test/resources/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..1d96ed4
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,101 @@
+
+
+
+ 4.0.0
+
+ ru.simplex_software
+ wicket-springdata
+ 1.0-SNAPSHOT
+
+ wicket-springdata
+
+ http://www.example.com
+
+
+ UTF-8
+ 1.8
+ 1.8
+
+
+
+
+ junit
+ junit
+ 4.11
+ test
+
+
+ org.springframework.data
+ spring-data-commons
+ 2.0.6.RELEASE
+
+
+ org.apache.wicket
+ wicket-core
+ 8.0.0-M7
+
+
+ org.apache.wicket
+ wicket-spring
+ 8.0.0-M7
+
+
+ org.hibernate
+ hibernate-core
+ 5.2.17.Final
+
+
+ org.springframework
+ spring-context
+ 5.0.5.RELEASE
+
+
+
+
+
+
+
+ maven-clean-plugin
+ 3.0.0
+
+
+
+ maven-resources-plugin
+ 3.0.2
+
+
+ maven-compiler-plugin
+ 3.7.0
+
+ 1.8
+ 1.8
+ UTF-8
+ true
+ true
+
+
+ -Xlint:unchecked
+
+
+
+
+ maven-surefire-plugin
+ 2.20.1
+
+
+ maven-jar-plugin
+ 3.0.2
+
+
+ maven-install-plugin
+ 2.5.2
+
+
+ maven-deploy-plugin
+ 2.8.2
+
+
+
+
+
diff --git a/src/main/java/ru/simplex_software/wicket_springdata/HibernateModel.java b/src/main/java/ru/simplex_software/wicket_springdata/HibernateModel.java
new file mode 100644
index 0000000..a8b6759
--- /dev/null
+++ b/src/main/java/ru/simplex_software/wicket_springdata/HibernateModel.java
@@ -0,0 +1,160 @@
+package ru.simplex_software.wicket_springdata;
+
+import org.apache.wicket.injection.Injector;
+import org.apache.wicket.model.LoadableDetachableModel;
+import org.apache.wicket.spring.injection.annot.SpringBean;
+import org.hibernate.Hibernate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.domain.Persistable;
+import org.springframework.data.repository.CrudRepository;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Модель содержит:
+ * Persistable сущность в прикреплённом состоянии,
+ * id и класс Persistable сущности в откреплённом состоянии.
+ */
+public class HibernateModel> extends LoadableDetachableModel {
+ private static final Logger LOG = LoggerFactory.getLogger(HibernateModel.class);
+
+ @SpringBean
+ private RepositoryFinder repositoryFinder;
+
+ /**
+ * Первичный кдюч хранимой сущности
+ */
+ private Serializable id;
+
+ /**
+ * Класс хранимой сущности
+ */
+ private Class tClass;
+
+ public HibernateModel() {
+ init();
+ }
+
+ /**
+ * Конструктор.
+ *
+ * @param entity может быть NULL.
+ */
+ public HibernateModel(T entity) {
+ super(entity);
+ init();
+ setObject(entity);
+ }
+
+ public void setObject(T entity) {
+ if (entity != null && entity.isNew()) {
+ throw new IllegalArgumentException("primary key can't be null");
+ }
+ super.setObject(entity);
+ }
+
+ /**
+ * Открепление сущности.
+ */
+ public void onDetach() {
+ LOG.debug("onDetach start");
+
+ // Получаем Persistable сущность.
+ T entity = getObject();
+ if (entity == null) {
+ return;
+ }
+
+ // Получаем Id и класс Persistable сущности.
+ id = entity.getId();
+ tClass = (Class) Hibernate.getClass(entity);
+ LOG.debug("onDetach end");
+ }
+
+ private void init() {
+ Injector.get().inject(this);
+ }
+
+ @Override
+ protected T load() {
+ LOG.debug("load start");
+
+ if (isAttached()) {
+ return getObject();
+ }
+ if (tClass == null) {
+ return null;
+ }
+ final CrudRepository repository = repositoryFinder.findRepository(tClass);
+ LOG.trace("repository={}", repository);
+ return (T) repository.findById(id).get();
+ }
+
+ /**
+ * Оборачивает в модели элементы списка.
+ */
+ public static > List> wrapElements(List list) {
+ final ArrayList> models = new ArrayList<>(list.size());
+ for (E e : list) {
+ models.add(new HibernateModel<>(e));
+ }
+ return models;
+ }
+
+ /**
+ * Оборачивает в модели элементы списка и возвращает итератор.
+ */
+ public static > Iterator> wrapAndIterateElements(List list) {
+ final ArrayList> models = new ArrayList<>(list.size());
+ for (E e : list) {
+ models.add(new HibernateModel<>(e));
+ }
+ return models.iterator();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (id == null) {
+ onDetach();
+ }
+ if (id == null) {//if no object set
+ if (o instanceof HibernateModel) {
+ Object obj = ((HibernateModel) o).getObject();
+ return obj == null;
+ }
+ return false;
+ }
+
+ if (o == null || getClass() != o.getClass()) return false;
+
+ HibernateModel> that = (HibernateModel>) o;
+
+ if (!id.equals(that.id)) return false;
+ return tClass.equals(that.tClass);
+ }
+
+ @Override
+ public int hashCode() {
+ if (id == null) {
+ onDetach(); // Для установки Id
+ }
+ if (id == null) { // if no object set
+ return -1;
+ } else {
+ return id.hashCode();
+ }
+ }
+
+ public RepositoryFinder getRepositoryFinder() {
+ return repositoryFinder;
+ }
+
+ public void setRepositoryFinder(RepositoryFinder repositoryFinder) {
+ this.repositoryFinder = repositoryFinder;
+ }
+}
diff --git a/src/main/java/ru/simplex_software/wicket_springdata/RepositoryFinder.java b/src/main/java/ru/simplex_software/wicket_springdata/RepositoryFinder.java
new file mode 100644
index 0000000..7b7ce55
--- /dev/null
+++ b/src/main/java/ru/simplex_software/wicket_springdata/RepositoryFinder.java
@@ -0,0 +1,67 @@
+package ru.simplex_software.wicket_springdata;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.data.domain.Persistable;
+import org.springframework.data.repository.CrudRepository;
+
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Находит подкласс репозитория.
+ */
+public class RepositoryFinder, K extends Serializable> implements ApplicationContextAware {
+ private static final Logger LOG = LoggerFactory.getLogger(RepositoryFinder.class);
+
+ private ApplicationContext applicationContext;
+
+ @Override
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ this.applicationContext = applicationContext;
+ }
+
+ /**
+ * Находит репизоторий по типу Persistable.
+ *
+ * @param tClass класс Persistable.
+ * @return первый CrudRepository для класса.
+ */
+ public CrudRepository findRepository(Class tClass) {
+ final Collection repositoryCollection = applicationContext.getBeansOfType(CrudRepository.class).values();
+
+ for (CrudRepository repository : repositoryCollection) {
+ final Class[] interfaces = repository.getClass().getInterfaces();
+ for (Class interfaze : interfaces) {
+ for (Type pt : interfaze.getGenericInterfaces()) {
+ if (!(pt instanceof ParameterizedType)) {
+ continue;
+ }
+ final Type[] actualTypeArguments = ((ParameterizedType) pt).getActualTypeArguments();
+ if (Arrays.asList(actualTypeArguments).contains(tClass)) {
+ return repository;
+ }
+ }
+ }
+ }
+ LOG.warn("repository not found. PersistentEntity={}", tClass.getName());
+ return null;
+ }
+
+ /**
+ * Находит репизоторий по типу репозитория Persistable.
+ *
+ * @param tClass класс Persistable.
+ * @return CrudRepository для класса.
+ */
+ public CrudRepository findRepositoryByClass(Class> tClass) {
+ final Collection> repositoryCollection = applicationContext.getBeansOfType(tClass).values();
+ return repositoryCollection.iterator().next();
+ }
+}
\ No newline at end of file