src/main/java/ru/indvdum/jpa/entities/AbstractEntity.groovy
author indvdum (gotoindvdum[at]gmail[dot]com)
Fri, 04 Jan 2013 02:22:39 +0400
changeset 22 55cb40622c14
parent 12 92ecc43feb3a
permissions -rw-r--r--
toString() fix
indvdum@2
     1
package ru.indvdum.jpa.entities
indvdum@2
     2
indvdum@2
     3
import java.lang.reflect.Modifier
indvdum@2
     4
indvdum@2
     5
import javax.persistence.EmbeddedId
indvdum@2
     6
import javax.persistence.Entity
indvdum@2
     7
import javax.persistence.Id
indvdum@2
     8
import javax.persistence.Transient
indvdum@2
     9
indvdum@2
    10
import org.apache.openjpa.util.OpenJPAId
indvdum@2
    11
import org.codehaus.jackson.map.ObjectMapper
indvdum@2
    12
indvdum@2
    13
import ru.indvdum.jpa.dao.JPADataAccessObject;
indvdum@2
    14
indvdum@2
    15
/**
indvdum@2
    16
 * @author 	indvdum (gotoindvdum@gmail.com)
indvdum@2
    17
 * @since 25.12.2011 13:26:57
indvdum@2
    18
 *
indvdum@2
    19
 */
indvdum@2
    20
abstract class AbstractEntity implements Serializable {
indvdum@2
    21
indvdum@2
    22
	@Transient
indvdum@2
    23
	protected ObjectMapper mapper = new ObjectMapper()
indvdum@2
    24
indvdum@2
    25
	@Override
indvdum@2
    26
	public String toString() {
indvdum@22
    27
		return getClass().getSimpleName() + '-' + getIdentifierValue()
indvdum@2
    28
	}
indvdum@2
    29
indvdum@2
    30
	/**
indvdum@2
    31
	 * JSON-like representation of an object
indvdum@2
    32
	 * 
indvdum@2
    33
	 * @return
indvdum@2
    34
	 */
indvdum@2
    35
	public String toJSON() {
indvdum@2
    36
		return mapper.writeValueAsString(this)
indvdum@2
    37
	}
indvdum@2
    38
indvdum@2
    39
	/* 
indvdum@2
    40
	 * HashCode, based on root class name of entity class hierarchy and id value 
indvdum@2
    41
	 * 
indvdum@2
    42
	 * (non-Javadoc)
indvdum@2
    43
	 * @see java.lang.Object#hashCode()
indvdum@2
    44
	 */
indvdum@2
    45
	@Override
indvdum@2
    46
	public int hashCode() {
indvdum@2
    47
		Class clazz = getClass()
indvdum@2
    48
		while (
indvdum@2
    49
			clazz.superclass != null
indvdum@2
    50
			&& !Modifier.isAbstract(clazz.superclass.modifiers)
indvdum@2
    51
			&& clazz.superclass.annotations.find {it instanceof Entity} != null
indvdum@2
    52
		)
indvdum@2
    53
			clazz = clazz.superclass
indvdum@2
    54
		String res = clazz.getName() + ': ' + getIdentifierValue()
indvdum@2
    55
		return res.hashCode()
indvdum@2
    56
	}
indvdum@2
    57
indvdum@2
    58
	/* 
indvdum@2
    59
	 * Comparison, based on entities id's
indvdum@2
    60
	 * 
indvdum@2
    61
	 * (non-Javadoc)
indvdum@2
    62
	 * @see java.lang.Object#equals(java.lang.Object)
indvdum@2
    63
	 */
indvdum@2
    64
	@Override
indvdum@2
    65
	public boolean equals(Object obj) {
indvdum@2
    66
		if(obj == null)
indvdum@2
    67
			return false
indvdum@2
    68
		if(!(obj.class.isAssignableFrom(this.class) || this.class.isAssignableFrom(obj.class)))
indvdum@2
    69
			return false
indvdum@2
    70
		def id = getIdentifierValue()
indvdum@2
    71
		def objId = (obj as AbstractEntity).getIdentifierValue()
indvdum@2
    72
		return id == objId || id != null && id != this && id.equals(objId)
indvdum@2
    73
	}
indvdum@2
    74
	
indvdum@2
    75
	/**
indvdum@2
    76
	 * @return The identifier value of an entity.
indvdum@2
    77
	 */
indvdum@2
    78
	@Transient
indvdum@2
    79
	public Object getIdentifierValue() {
indvdum@2
    80
		// an attempt to get id by EntityManagerFactory
indvdum@2
    81
		Object identifier = JPADataAccessObject.emf.getPersistenceUnitUtil().getIdentifier(this)
indvdum@2
    82
		if(identifier instanceof OpenJPAId)
indvdum@2
    83
			return ((OpenJPAId)identifier).getIdObject()
indvdum@2
    84
		
indvdum@2
    85
		def result
indvdum@2
    86
		
indvdum@2
    87
		// an attempt to find id by annotated fields
indvdum@2
    88
		Class clazz = getClass()
indvdum@2
    89
		def self = this
indvdum@2
    90
		Collection fields = clazz.declaredFields
indvdum@2
    91
		while(clazz.superclass != null) {
indvdum@2
    92
			clazz = clazz.superclass
indvdum@2
    93
			fields.addAll(clazz.declaredFields)
indvdum@2
    94
		}
indvdum@2
    95
		fields.grep {
indvdum@2
    96
			!it.synthetic &&
indvdum@2
    97
					!Modifier.isStatic(it.modifiers) &&
indvdum@2
    98
					!Modifier.isTransient(it.modifiers)
indvdum@2
    99
		}.grep {
indvdum@2
   100
			it.annotations.find {
indvdum@2
   101
				it instanceof Id || it instanceof EmbeddedId
indvdum@2
   102
			} != null
indvdum@2
   103
		}.each {
indvdum@2
   104
			boolean isAccessible = it.accessible
indvdum@2
   105
			it.accessible = true
indvdum@2
   106
			result = it.get(self)
indvdum@2
   107
			it.accessible = isAccessible
indvdum@2
   108
		}
indvdum@2
   109
		if(result != null && !(result instanceof Reference && (result as Reference).value == null))
indvdum@2
   110
			return result
indvdum@2
   111
		
indvdum@2
   112
		// an attempt to represent id as a aggregate of all fields
indvdum@2
   113
		// TODO check, why toJSON method don't work
indvdum@2
   114
//		return toJSON()
indvdum@2
   115
		result = '{'
indvdum@2
   116
		fields.grep {
indvdum@2
   117
			!it.synthetic &&
indvdum@2
   118
					!Modifier.isStatic(it.modifiers) &&
indvdum@2
   119
					!Modifier.isTransient(it.modifiers)
indvdum@2
   120
		}.grep {
indvdum@2
   121
			it.annotations.find {
indvdum@2
   122
				it instanceof Transient
indvdum@2
   123
			} == null
indvdum@2
   124
		}.each {
indvdum@2
   125
			boolean isAccessible = it.accessible
indvdum@2
   126
			it.accessible = true
indvdum@2
   127
			result += '"' + it.name + '": "' + it.get(self) + '", '
indvdum@2
   128
			it.accessible = isAccessible
indvdum@2
   129
		}
indvdum@2
   130
		return result
indvdum@2
   131
	}
indvdum@12
   132
	
indvdum@12
   133
	protected def callMethod(method, Object ... args) {
indvdum@12
   134
		"$method"(*args)
indvdum@12
   135
	}
indvdum@2
   136
}