/*
* Copyright 2013 Guidewire Software, Inc.
*/
package gw.internal.gosu.parser;
import gw.config.CommonServices;
import gw.lang.GosuShop;
import gw.lang.javadoc.IDocRef;
import gw.lang.javadoc.IClassDocNode;
import gw.lang.javadoc.IConstructorNode;
import gw.lang.javadoc.IExceptionNode;
import gw.lang.javadoc.IParamNode;
import gw.lang.parser.TypeVarToTypeMap;
import gw.lang.reflect.IAnnotationInfo;
import gw.lang.reflect.IConstructorHandler;
import gw.lang.reflect.IExceptionInfo;
import gw.lang.reflect.IFeatureInfo;
import gw.lang.reflect.IParameterInfo;
import gw.lang.reflect.IType;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.IScriptabilityModifier;
import gw.lang.reflect.java.*;
import gw.util.GosuExceptionUtil;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
/**
*/
public class JavaConstructorInfo extends JavaBaseFeatureInfo implements IJavaConstructorInfo
{
private IJavaClassConstructor _ctor;
private IParameterInfo[] _params;
private IConstructorHandler _ctorHandler;
private List<IExceptionInfo> _exceptions;
private IDocRef<IConstructorNode> _docs = new IDocRef<IConstructorNode>() {
@Override
public IConstructorNode get() {
IClassDocNode classDocs = ((JavaTypeInfo)getContainer()).getDocNode().get();
return classDocs == null ? null : classDocs.getConstructor(_ctor);
}
};
/**
* @param container Typically this will be the containing ITypeInfo
* @param ctor The java ctor
*/
public JavaConstructorInfo(IFeatureInfo container, IJavaClassConstructor ctor) {
super(container);
_ctor = ctor;
if (_ctor instanceof ConstructorJavaClassConstructor) {
((ConstructorJavaClassConstructor)_ctor).setAccessible(true);
}
}
@Override
public IJavaClassConstructor getJavaConstructor()
{
return _ctor;
}
public Constructor getRawConstructor()
{
return ((ConstructorJavaClassConstructor)_ctor).getJavaConstructor();
}
@Override
public boolean isDefault() {
return _ctor.isDefault();
}
@Override
public IType getType()
{
return getOwnersType();
}
@Override
public IParameterInfo[] getGenericParameters()
{
return getParameters( true );
}
@Override
public IParameterInfo[] getParameters()
{
IType ownerType = getOwnersType();
return getParameters( !ownerType.isGenericType() || ownerType.isParameterizedType() );
}
private IParameterInfo[] getParameters( boolean bKeepTypeVars )
{
if( _params != null && !bKeepTypeVars )
{
return _params;
}
TypeVarToTypeMap actualParamByVarName = TypeLord.mapTypeByVarName( getOwnersType(), getType(), bKeepTypeVars );
IParameterInfo[] params = _ctor.convertGenericParameterTypes( this, actualParamByVarName, bKeepTypeVars );
if( !bKeepTypeVars )
{
_params = params;
}
return params;
}
@Override
public IConstructorHandler getConstructor()
{
if( _ctorHandler == null )
{
_ctorHandler = new ConstructorHandlerAdapter();
}
return _ctorHandler;
}
@Override
public List<IAnnotationInfo> getDeclaredAnnotations() {
List<IAnnotationInfo> annotations = super.getDeclaredAnnotations();
if (getConstructorDocs().get() != null && getConstructorDocs().get().isDeprecated()) {
annotations.add(GosuShop.getAnnotationInfoFactory().createJavaAnnotation(makeDeprecated(getConstructorDocs().get().getDeprecated()), this));
}
return annotations;
}
private IDocRef<IConstructorNode> getConstructorDocs() {
return _docs;
}
@Override
public List<IExceptionInfo> getExceptions() {
if (_exceptions == null) {
IJavaClassInfo[] classes = _ctor.getExceptionTypes();
_exceptions = new ArrayList<IExceptionInfo>();
for ( final IJavaClassInfo exceptionClass : classes ) {
_exceptions.add( new JavaExceptionInfo( this, exceptionClass, new IDocRef<IExceptionNode>() {
@Override
public IExceptionNode get() {
return getConstructorDocs().get() == null ? null : getConstructorDocs().get().getException( exceptionClass );
}
} ) );
}
}
// merge in methods exceptions with the annotations
return _exceptions;
}
@Override
public String getName() {
return makeSignature();
}
private String makeSignature() {
String name = getDisplayName();
name += "(";
IParameterInfo[] parameterInfos = getParameters();
if (parameterInfos.length > 0) {
name += " ";
for (int i = 0; i < parameterInfos.length; i++) {
IParameterInfo iParameterInfo = getParameters()[i];
if (i != 0) {
name += ", ";
}
name += iParameterInfo.getFeatureType().getName();
}
name += " ";
}
name += ")";
return name;
}
@Override
public String getDisplayName()
{
return getOwnersType().getRelativeName();
}
public String getShortDescription()
{
return getConstructorDocs().get() != null ? getConstructorDocs().get().getDescription() : null;
}
@Override
public String getDescription()
{
return getConstructorDocs().get() != null ? getConstructorDocs().get().getDescription() : null;
}
@Override
public boolean isStatic()
{
return true;
}
@Override
public boolean isPrivate()
{
return java.lang.reflect.Modifier.isPrivate( _ctor.getModifiers() );
}
@Override
public boolean isInternal()
{
return !isPrivate() && !isPublic() && !isProtected();
}
@Override
public boolean isProtected()
{
return Modifier.isProtected( _ctor.getModifiers() );
}
@Override
public boolean isPublic()
{
return Modifier.isPublic( _ctor.getModifiers() );
}
@Override
public boolean isAbstract()
{
return Modifier.isAbstract( _ctor.getModifiers() );
}
@Override
public IDocRef<IParamNode> getDocsForParam(final int paramIndex) {
return new IDocRef<IParamNode>() {
@Override
public IParamNode get() {
return getConstructorDocs().get() == null ? null : getConstructorDocs().get().getParams().get(paramIndex);
}
};
}
@Override
public boolean isFinal()
{
return Modifier.isFinal( _ctor.getModifiers() );
}
public boolean isSynthetic()
{
return _ctor instanceof IJavaClassBytecodeConstructor && ((IJavaClassBytecodeConstructor)_ctor).isSynthetic();
}
private final class ConstructorHandlerAdapter implements IConstructorHandler
{
@Override
public Object newInstance( Object... args )
{
ClassLoader previousClassLoader = Thread.currentThread().getContextClassLoader();
if(TypeSystem.getCurrentModule() != null) {
Thread.currentThread().setContextClassLoader( TypeSystem.getGosuClassLoader().getActualLoader() ); //_ctor.getDeclaringClass().getClassLoader() );
}
try
{
if( args == null || args.length == 0 )
{
return _ctor.newInstance( null );
}
return _ctor.newInstance( CommonServices.getEntityAccess().convertToExternalIfNecessary( args, ((ConstructorJavaClassConstructor)_ctor).getJavaParameterTypes(), ((ConstructorJavaClassConstructor)_ctor).getDeclaringJavaClass() ) );
}
catch( IllegalArgumentException e )
{
GosuExceptionUtil.throwArgMismatchException( e, "a constructor", ((ConstructorJavaClassConstructor)_ctor).getJavaParameterTypes(), args );
return null;
}
catch( InvocationTargetException ex )
{
throw GosuExceptionUtil.forceThrow( ex.getTargetException() );
}
catch( Throwable t )
{
throw GosuExceptionUtil.forceThrow( t );
}
finally
{
Thread.currentThread().setContextClassLoader( previousClassLoader );
}
}
}
@Override
protected IJavaAnnotatedElement getAnnotatedElement()
{
return _ctor;
}
@Override
protected boolean isVisibleViaFeatureDescriptor(IScriptabilityModifier constraint) {
return true;
}
@Override
protected boolean isHiddenViaFeatureDescriptor() {
return false;
}
@Override
protected boolean isDefaultEnumFeature()
{
return true;
}
}