/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.parser;
import gw.config.CommonServices;
import gw.internal.gosu.parser.java.classinfo.CompileTimeExpressionParser;
import gw.internal.gosu.parser.java.classinfo.JavaSourceEnumConstant;
import gw.internal.gosu.parser.java.classinfo.JavaSourceField;
import gw.lang.Deprecated;
import gw.lang.GosuShop;
import gw.lang.javadoc.IClassDocNode;
import gw.lang.javadoc.IDocRef;
import gw.lang.javadoc.IVarNode;
import gw.lang.parser.EvaluationException;
import gw.lang.parser.IExpression;
import gw.lang.reflect.FeatureManager;
import gw.lang.reflect.IAnnotationInfo;
import gw.lang.reflect.IFeatureInfo;
import gw.lang.reflect.IPresentationInfo;
import gw.lang.reflect.IPropertyAccessor;
import gw.lang.reflect.IRelativeTypeInfo;
import gw.lang.reflect.IScriptabilityModifier;
import gw.lang.reflect.IType;
import gw.lang.reflect.java.IJavaAnnotatedElement;
import gw.lang.reflect.java.IJavaClassField;
import gw.lang.reflect.java.IJavaFieldPropertyInfo;
import gw.lang.reflect.java.IJavaType;
import gw.util.GosuExceptionUtil;
import java.lang.reflect.Modifier;
import java.util.List;
/**
*/
public class JavaFieldPropertyInfo extends JavaBaseFeatureInfo implements IJavaFieldPropertyInfo
{
private IJavaClassField _field;
private boolean _isStatic;
private IType _type;
private IPropertyAccessor _accessor;
private String _strName;
private IDocRef<IVarNode> _docs = new IDocRef<IVarNode>() {
@Override
public IVarNode get() {
if (getContainer() instanceof JavaTypeInfo) {
IClassDocNode classDocs = ((JavaTypeInfo) getContainer()).getDocNode().get();
@SuppressWarnings({"UnnecessaryLocalVariable"})
IVarNode varDoc = classDocs == null ? null : classDocs.getVar( _field.getName() );
return varDoc;
} else {
return null;
}
}
};
JavaFieldPropertyInfo(IFeatureInfo container, IType type, IJavaClassField field, boolean isStatic)
{
super( container );
if (type == null) {
throw new IllegalArgumentException("Feature type cannot be null");
}
_type = type;
_field = field;
if (_field instanceof FieldJavaClassField) {
((FieldJavaClassField)_field).setAccessible( true );
}
_isStatic = isStatic;
//_strName = NewIntrospector.capitalizeFirstChar( _field.getName() ).replace( '$', '_' );
_strName = _field.getName().replace( '$', '_' );
if( _isStatic )
{
_accessor = new StaticAccessor();
}
else
{
_accessor = new NonStaticAccessor();
}
}
@Override
public String getName()
{
return _strName;
}
void changeNameForNonStaticCollision()
{
_strName += "_";
}
@Override
public IType getFeatureType()
{
return _type;
}
@Override
public boolean isStatic()
{
return _isStatic;
}
@Override
public boolean isReadable()
{
return true;
}
@Override
public boolean isWritable(IType whosAskin) {
IRelativeTypeInfo.Accessibility accessibilityForType = ((IRelativeTypeInfo) getContainer()).getAccessibilityForType(whosAskin);
return !Modifier.isFinal( _field.getModifiers() ) && FeatureManager.isFeatureAccessible(this, accessibilityForType);
}
@Override
public boolean isWritable()
{
return isWritable(null);
}
@Override
public boolean isDeprecated()
{
return super.isDeprecated() || getField().isAnnotationPresent( gw.lang.Deprecated.class );
}
@Override
public String getDeprecatedReason()
{
String deprecated = super.getDeprecatedReason();
if( isDeprecated() && deprecated == null )
{
return (String) getField().getAnnotation( Deprecated.class ).getFieldValue("value");
}
return deprecated;
}
@Override
public boolean isPrivate()
{
return Modifier.isPrivate( _field.getModifiers() );
}
@Override
public boolean isInternal()
{
return !isPrivate() && !isProtected() && !isPublic();
}
@Override
public boolean isProtected()
{
return Modifier.isProtected( _field.getModifiers() );
}
@Override
public boolean isPublic()
{
return Modifier.isPublic( _field.getModifiers() );
}
@Override
public String getDescription()
{
return getVarDocs().get() == null ? null : getVarDocs().get().getDescription();
}
private IDocRef<IVarNode> getVarDocs() {
return _docs;
}
@Override
public IPropertyAccessor getAccessor()
{
return _accessor;
}
@Override
public List<IAnnotationInfo> getDeclaredAnnotations()
{
List<IAnnotationInfo> annotations = super.getDeclaredAnnotations();
if( getVarDocs().get() != null && getVarDocs().get().isDeprecated() )
{
annotations.add( GosuShop.getAnnotationInfoFactory().createJavaAnnotation(makeDeprecated( getVarDocs().get().getDeprecated() ), this ) );
}
return annotations;
}
@Override
public IPresentationInfo getPresentationInfo()
{
return IPresentationInfo.Default.GET;
}
@Override
public IJavaClassField getField()
{
return _field;
}
@Override
public String toString() {
return getName();
}
@Override
protected IJavaAnnotatedElement getAnnotatedElement()
{
return _field;
}
@Override
protected boolean isVisibleViaFeatureDescriptor(IScriptabilityModifier constraint) {
return true;
}
@Override
protected boolean isHiddenViaFeatureDescriptor() {
return false;
}
@Override
protected boolean isDefaultEnumFeature()
{
return false;
}
@Override
public String getReturnDescription() {
return null;
}
@Override
public boolean isCompileTimeConstantValue() {
return Modifier.isStatic( getField().getModifiers() ) &&
Modifier.isFinal( getField().getModifiers() ) && isCompileTimeConstant();
}
private boolean isCompileTimeConstant() {
IJavaClassField field = getField();
if( field instanceof JavaSourceEnumConstant ) {
return true;
}
else if( field instanceof JavaSourceField ) {
String rhs = ((JavaSourceField)field).getRhs();
if( rhs == null ) {
return false;
}
IExpression pr = CompileTimeExpressionParser.parse( rhs, field.getEnclosingClass(), getFeatureType() );
return pr.isCompileTimeConstant();
}
else if( field instanceof AsmFieldJavaClassField &&
((AsmFieldJavaClassField)field).getStaticValue() != null ) {
return true;
}
else if( field instanceof FieldJavaClassField || field instanceof AsmFieldJavaClassField ) {
return field.isEnumConstant() ||
field.getType().isPrimitive() ||
field.getType().getName().equals( "java.lang.String" ) ||
field.getType().getName().equals( "java.lang.Class" );
}
return false;
}
@Override
public Object doCompileTimeEvaluation() {
//((IJavaType)getOwnersType()).getBackingClassInfo().getDeclaredFields()
IJavaClassField field = getField();
if( field instanceof JavaSourceEnumConstant ) {
return field.getName();
}
else if( field instanceof JavaSourceField ) {
String rhs = ((JavaSourceField)field).getRhs();
IExpression pr = CompileTimeExpressionParser.parse( rhs, ((IJavaType)getOwnersType()).getBackingClassInfo(), getFeatureType() );
return pr.evaluate();
}
else if( field instanceof FieldJavaClassField ) {
try {
Object value = ((FieldJavaClassField)field).get( null );
return CompileTimeExpressionParser.convertValueToInfoFriendlyValue( value, getOwnersType().getTypeInfo() );
}
catch( IllegalAccessException e ) {
throw new RuntimeException( e );
}
}
else if( field instanceof AsmFieldJavaClassField ) {
if( field.isEnumConstant() ) {
return field.getName();
}
Object value = ((AsmFieldJavaClassField)field).getStaticValue();
return CompileTimeExpressionParser.convertValueToInfoFriendlyValue( value, getOwnersType().getTypeInfo() );
}
else {
throw new IllegalStateException( "Unexpected field type: " + field );
}
}
private class StaticAccessor implements IPropertyAccessor
{
@Override
public Object getValue( Object ctx )
{
try
{
return ((FieldJavaClassField)_field).get( null );
}
catch( IllegalAccessException e )
{
throw GosuExceptionUtil.forceThrow( e );
}
}
@Override
public void setValue( Object ctx, Object value )
{
if( !isWritable( getOwnersType()) )
{
throw new EvaluationException( "Property, " + getName() + ", is not writable!" );
}
try
{
value = CommonServices.getCoercionManager().convertValue( value, getFeatureType() );
((FieldJavaClassField)_field).set( null, value );
}
catch( IllegalAccessException e )
{
throw GosuExceptionUtil.forceThrow( e );
}
}
}
private class NonStaticAccessor implements IPropertyAccessor
{
@Override
public Object getValue( Object ctx )
{
try
{
return ((FieldJavaClassField)_field).get( ctx );
}
catch( IllegalAccessException e )
{
throw GosuExceptionUtil.forceThrow( e );
}
}
@Override
public void setValue( Object ctx, Object value )
{
if( !isWritable( getOwnersType()) )
{
throw new EvaluationException( "Property, " + getName() + ", is not writable!" );
}
try
{
value = CommonServices.getCoercionManager().convertValue( value, getFeatureType() );
((FieldJavaClassField)_field).set( ctx, value );
}
catch( IllegalAccessException e )
{
throw GosuExceptionUtil.forceThrow( e );
}
}
}
}