/** * Copyright 2015 Santhosh Kumar Tekuri * * The JLibs authors license this file to you under the Apache License, * version 2.0 (the "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. */ package jlibs.jdbc.annotations.processor; import jlibs.core.annotation.processing.AnnotationError; import jlibs.core.lang.ClassUtil; import jlibs.core.lang.StringUtil; import jlibs.core.lang.model.ModelUtil; import jlibs.jdbc.JavaType; import jlibs.jdbc.SQLType; import jlibs.jdbc.annotations.References; import jlibs.jdbc.annotations.Table; import jlibs.jdbc.annotations.TypeMapper; import javax.lang.model.element.AnnotationMirror; import javax.lang.model.element.AnnotationValue; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; /** * @author Santhosh Kumar T */ abstract class ColumnProperty<E extends Element>{ public E element; public AnnotationMirror annotation; protected ColumnProperty(E element, AnnotationMirror annotation){ this.element = element; this.annotation = annotation; } public String columnName(){ String columnName = ModelUtil.getAnnotationValue((Element) element, annotation, "name"); return columnName.length()==0 ? StringUtil.underscore(propertyName()) : columnName; } public String columnName(boolean quoted){ String columnName = columnName(); if(quoted) return String.format("jdbc.quote(\"%s\")", StringUtil.toLiteral(columnName, true)); else return StringUtil.toLiteral(columnName, true); } public boolean primary(){ return (Boolean)ModelUtil.getAnnotationValue((Element)element, annotation, "primary"); } public boolean auto(){ return (Boolean)ModelUtil.getAnnotationValue((Element)element, annotation, "auto"); } public boolean nativeType(){ return (Boolean)ModelUtil.getAnnotationValue((Element)element, annotation, "nativeType"); } protected AnnotationMirror typeMapperMirror(){ return ModelUtil.getAnnotationMirror(element, TypeMapper.class); } public TypeMirror javaTypeMirror(){ AnnotationMirror typeMapperMirror = typeMapperMirror(); if(typeMapperMirror==null) return propertyType(); else return (DeclaredType)ModelUtil.getAnnotationValue(element, typeMapperMirror, "mapsTo"); } public String resultSetType(){ TypeMirror propertyType = javaTypeMirror(); boolean primitive = ModelUtil.isPrimitive(propertyType); boolean primitiveWrapper = ModelUtil.isPrimitiveWrapper(propertyType); if(primitive) return ModelUtil.toString(propertyType, false); else if(primitiveWrapper){ String type = ModelUtil.toString(propertyType, false); return ModelUtil.getPrimitive(type); }else if(javaType()==JavaType.OTHER) return Object.class.getName(); else return ModelUtil.toString(propertyType, false); } public JavaType javaType(){ try{ Class propertyType = Class.forName(ModelUtil.toString(javaTypeMirror(), true)); propertyType = ClassUtil.unbox(propertyType); JavaType javaType = JavaType.valueOf(propertyType); if(javaType==null) return nativeType() ? JavaType.OTHER : null; else return javaType; }catch(ClassNotFoundException ex){ return null; } } public SQLType sqlType(){ return javaType().sqlTypes[0]; } public TypeMirror typeMapper(){ AnnotationMirror mirror = typeMapperMirror(); return mirror==null ? null : (DeclaredType)ModelUtil.getAnnotationValue(element, mirror, "mapper"); } public abstract String propertyName(); public abstract TypeMirror propertyType(); public abstract String getPropertyCode(String object); public abstract String setPropertyCode(String object, String value); public String[] getValueFromResultSet(int index){ String resultSetType = resultSetType(); int dot = resultSetType.lastIndexOf('.'); if(dot!=-1) resultSetType = resultSetType.substring(dot+1); if(ModelUtil.isPrimitive(javaTypeMirror()) || ModelUtil.isPrimitiveWrapper(javaTypeMirror())){ String name = propertyName(); return new String[]{ resultSetType+' '+name+" = rs.get"+StringUtil.capitalize(resultSetType)+'('+index+");", "rs.wasNull() ? null : "+name }; }else return new String[]{ "rs.get"+StringUtil.capitalize(resultSetType)+'('+index+')' }; } @Override public int hashCode(){ return propertyName().hashCode(); } @Override public boolean equals(Object that){ return that instanceof ColumnProperty && ((ColumnProperty)that).propertyName().equals(this.propertyName()); } // ensure that propertyType is valid javaType that can be fetched from ResultSet public void validateType(){ if(javaType()==null) throw new AnnotationError(element, annotation, resultSetType()+" has no mapping SQL Type"); } public String toNativeTypeCode(String value){ TypeMirror typeMirror = typeMapper(); if(typeMirror!=null) value = "TYPE_MAPPER_"+StringUtil.underscore(propertyName()).toUpperCase()+".userToNative("+value+")"; return value; } public String toUserTypeCode(String value){ TypeMirror typeMirror = typeMapper(); if(typeMirror!=null) value = "TYPE_MAPPER_"+StringUtil.underscore(propertyName()).toUpperCase()+".nativeToUser("+value+")"; return value; } public Reference reference; } class Reference{ public final TypeElement tableClass; public final String columnName; Reference(TypeElement tableClass, String columnName){ this.tableClass = tableClass; this.columnName = columnName; } public Columns table(){ return Columns.ALL.get(tableClass); } public ColumnProperty column(){ return table().findByProperty(columnName); } public static Reference find(Element element){ AnnotationMirror mirror = ModelUtil.getAnnotationMirror(element, References.class); if(mirror!=null){ AnnotationValue tableAnnotationValue = ModelUtil.getRawAnnotationValue(element, mirror, "table"); TypeElement tableClass = (TypeElement)((DeclaredType)tableAnnotationValue.getValue()).asElement(); if(ModelUtil.getAnnotationMirror(tableClass, Table.class)==null) throw new AnnotationError(element, mirror, tableAnnotationValue, "Reference class "+tableClass.getQualifiedName()+" doesn't has @Table annotation"); String columnName = ModelUtil.getAnnotationValue(element, mirror, "column"); return new Reference(tableClass, columnName); }else return null; } }