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