Bug 472450 - cannot convert from element type Object to String
Summary: cannot convert from element type Object to String
Status: VERIFIED INVALID
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.7.2   Edit
Hardware: PC Linux
: P3 minor (vote)
Target Milestone: 4.6 M1   Edit
Assignee: Stephan Herrmann CLA
QA Contact:
URL:
Whiteboard:
Keywords: needinfo
Depends on:
Blocks:
 
Reported: 2015-07-12 21:32 EDT by Ricardo Wolosker CLA
Modified: 2015-08-04 00:58 EDT (History)
3 users (show)

See Also:


Attachments
Compile.java (rev 783) (6.59 KB, text/plain)
2015-07-13 09:35 EDT, Ricardo Wolosker CLA
no flags Details
Compile.java (rev 790) (5.53 KB, text/plain)
2015-07-13 09:39 EDT, Ricardo Wolosker CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Ricardo Wolosker CLA 2015-07-12 21:32:57 EDT
I'm trying to compile a class within the application.It is giving error in the page structure for-each. I tried setting the compilation by compilerOptions, but can not find a property to configure properly.

this is the class section I want to build and that is a problem.

public class Essa{
  @In
  private Script script;
  @In
  private Context context;

  public void main()throws Exception{
    for(String key:context.keys()){
      script.print(key+":"+context.getValue(key));
    }

  }
}


Caused by: java.lang.Error: Unresolved compilation problem:
	Type mismatch: cannot convert from element type Object to String



I'm calling the Compiler manually because I could not set the classpath to work with situations of the type on-the-fly.

I've checked the output of compilerOptions properties and are identical (diff) when I use the EclipseCompiler. Is it necessary to make any other setting?

This is the piece of code that I do to compile the class.


      compilerOptions.sourceLevel=ClassFileConstants.JDK1_6;
      compilerOptions.targetJDK=ClassFileConstants.JDK1_6;
      compilerOptions.complianceLevel=ClassFileConstants.JDK1_6;
      compilerOptions.processAnnotations=true;
      compilerOptions.verbose=true;
      compilerOptions.produceReferenceInfo=true;
      compilerOptions.storeAnnotations=true;
      compilerOptions.performMethodsFullRecovery=false;
      compilerOptions.performStatementsRecovery=false;
      compilerOptions.inlineJsrBytecode=true;
      
      
      
      compiler=new Compiler(
        fileSystem(),  
        new Policy(),
        compilerOptions,
        requestor,
        new DefaultProblemFactory(),
        out,
        null
      );
      
      units=new ICompilationUnit[]{
        new CompilationUnit(code.toCharArray(),filename.replaceAll("\\.","/"),null)
      };
           
      compiler.compile(units);
      
      return byteClassLoader.loadClass(filename);
Comment 1 Jay Arthanareeswaran CLA 2015-07-13 01:59:21 EDT
This may not be related to the compiler API or the compiler options at all. Can you tell us what "Context" looks like? Without looking at it, I can only guess that you need to parameterize the context instance with String to be able to use it without a cast.
Comment 2 Ricardo Wolosker CLA 2015-07-13 09:35:58 EDT
Created attachment 255164 [details]
Compile.java (rev 783)

this is the version that works, but only compiles when it runs within the Eclipse or java-app. If run from within an application server, it does not.

I saw the source of ecj-3.7.2 API that when an extended class JavaFileManager is used, the routine retrieves the classpath parameters is not performed, only used the bootclasspath.
Comment 3 Ricardo Wolosker CLA 2015-07-13 09:39:56 EDT
Created attachment 255166 [details]
Compile.java (rev 790)

this is the version that works with problem solved classpath. The problem is that is not working the like

List <String> names = ...
for (String name: names)
Comment 4 Stephan Herrmann CLA 2015-07-13 10:37:15 EDT
Recardo, just from looking at the code that invokes the compiler it will be very hard / impossible to find out what's happening. Could you provide a simple main method and the full set of files to be compiled so that we can reproduce?  As Jay mentioned, we'd need at least the signatures of type Context.

The only bad smell I can see so far is the direct manipulation of fields of CompilerOptions rather than calling CompilerOptions.set(..) but that could well be a red herring.
Comment 5 Ricardo Wolosker CLA 2015-07-14 20:19:06 EDT
the problem is "checkedClasspaths" the org.eclipse.jdt.internal.compiler.tool.EclipseCompilerImpl class. There is no way to inform other API if they are not defined in sun.boot.class.path

9. ERROR in /esse/teste/Esse.java (at line 15)
script.print (String.format ("% s:% s"
^^^^^^
Script can not be resolved to a type
Comment 6 Ricardo Wolosker CLA 2015-07-14 20:56:58 EDT
org.eclipse.jdt.internal.compiler.tool.EclipseCompilerImpl

	protected void setPaths(ArrayList bootclasspaths,
			String sourcepathClasspathArg,
			ArrayList sourcepathClasspaths,
			ArrayList classpaths,
			ArrayList extdirsClasspaths,
			ArrayList endorsedDirClasspaths,
			String customEncoding) {

		ArrayList<FileSystem.Classpath> fileSystemClasspaths = new ArrayList<FileSystem.Classpath>();
		EclipseFileManager javaFileManager = null;
		StandardJavaFileManager standardJavaFileManager = null;

    
		if (this.fileManager instanceof EclipseFileManager) {
			javaFileManager = (EclipseFileManager) this.fileManager;
		}

		if (this.fileManager instanceof StandardJavaFileManager) {
			standardJavaFileManager = (StandardJavaFileManager) this.fileManager;
		}



Esse trecho de código impede a customização do StandardJavaFileManager, impondo o uso da componente EclipseFileManager. Para completar todas as API do classPath, é necessário override este método


    public Iterable<? extends File> getLocation(Location location){
      if(!location.equals(StandardLocation.CLASS_PATH))
        return super.getLocation(location);
      
      List<File>files=new ArrayList<File>();
      URLClassLoader urlClassLoader=(URLClassLoader)classLoadCompile;
      
      for(URL url:urlClassLoader.getURLs()){
        files.add(new File(url.getPath()));
      }
      return files;
    }
Comment 7 Ricardo Wolosker CLA 2015-07-14 20:57:40 EDT
Consegui resolver com essa classe:

/********************************************************************

********************************************************************/  
package eala.command;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Serializable;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import javax.tools.Diagnostic;
import javax.tools.DiagnosticListener;
import javax.tools.FileObject;
import javax.tools.JavaCompiler;
import javax.tools.SimpleJavaFileObject;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardLocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.jdt.internal.compiler.tool.EclipseCompiler;
import org.eclipse.jdt.internal.compiler.tool.EclipseCompilerImpl;
import org.eclipse.jdt.internal.compiler.tool.EclipseFileManager;

public class Compile implements Serializable{
  private static final long serialVersionUID=1L;
  private Log log=LogFactory.getLog(getClass());
  private ByteArrayOutputStream writerStream=null;
  private PrintWriter writer=null;
  private JavaCompiler javac=null;
  private FileManager fileManager=null;
  private ClassLoader classLoadCompile=null;
  private ClassLoader classLoadCurrent=null;
  private ClassLoadFactory classLoadFactory;
  private DiagnosticListener diagnosticListener=null;
  private List<String>options=new ArrayList<String>();
  private List<String>classes=null;
  private CompilationTask task=null;
  private List<CompileUnit>archives=null;
  private boolean compiled=false;
  /*=======================================================
   
  =======================================================*/
  public Class compile(String source,String className){
    log.debug(className);
    try{
      archives=new ArrayList<CompileUnit>();
      diagnosticListener=new CDiagnosticListener();
      classLoadCurrent=Thread.currentThread().getContextClassLoader();
      classLoadCompile=classLoadCompile();
      classLoadFactory=new ClassLoadFactory();
      writerStream=new ByteArrayOutputStream();
      writer=new PrintWriter(writerStream);
      javac=new EclipseCompiler();
      fileManager=new FileManager(null,null);
      options.add("-verbose");
          
      task=javac.getTask(
        writer,
        fileManager,
        diagnosticListener,
        options,
        classes,
        createCompileUnit(source,className)
      );
      compiled=task.call();
      
      if(!compiled)
        throw new RuntimeException(new String(writerStream.toByteArray()));
      
      appendClass();
      return classLoadFactory.loadClass(className);
    }
    catch(Exception e){
      throw new RuntimeException(e);
    }
    finally{
      try{writer.close();}catch(Exception e){}        
      try{writerStream.close();}catch(Exception e){}
      try{for(CompileUnit c:archives)c.close();}catch(Exception e){}
    }
  }
  /*=======================================================
   
  =======================================================*/
  private void appendClass(){
    for(CompileUnit c:archives){
      if(c.getKind()==Kind.CLASS){
        log.debug(String.format("append : %s",fileNameToClassName(c.getFileName())));
        classLoadFactory.appendClass(
          fileNameToClassName(c.getFileName()),
          c.getBytes()
        );
      }
    }
  }
  /*=======================================================
   
  =======================================================*/
  private class ClassLoadFactory extends ClassLoader implements Serializable{
    private static final long serialVersionUID=1L;
    public ClassLoadFactory(){
      super(classLoadCurrent);
    }
    public void appendClass(String className,byte[]b){
      defineClass(className,b,0,b.length);
    }
  }
  /*=======================================================
   
  =======================================================*/
  private class CompileUnit extends SimpleJavaFileObject implements Serializable{
    private static final long serialVersionUID=1L;
    private String source=null;
    private String fileName=null;
    private ByteArrayOutputStream outputStream=null;
    private ByteArrayInputStream inputStream=null;
    public CompileUnit(String source,String fileName,Kind kind){
      super(URI.create(fileName),kind);     
      log.debug(String.format("compileUnit: %s",fileName));
      this.source=source;
      this.fileName=fileName;
      archives.add(this);
    }
    public CharSequence getCharContent(boolean ignoreEncodingErrors){      
      return source;  
    }  
    public InputStream openInputStream() {      
      return inputStream=new ByteArrayInputStream(source.getBytes());  
    }
    public OutputStream openOutputStream() throws IOException{
      return outputStream=new ByteArrayOutputStream();
    }
    public byte[]getBytes(){      
      return outputStream.toByteArray();  
    }
    public void close(){
      try{inputStream.close();}catch(Exception e){}
      try{outputStream.close();}catch(Exception e){}
    }
    public String getFileName(){return fileName;}
  }
  /*=======================================================
   
  =======================================================*/
  private ClassLoader classLoadCompile()throws Exception{
    String bootPath=System.getProperty("sun.boot.class.path");
    String pathSeparator=System.getProperty("path.separator");
    List<URL>urls=new ArrayList<URL>();
   
    for(String url:bootPath.split("\\"+pathSeparator))
      urls.add(new File(url).toURI().toURL());
    for(URL url:((URLClassLoader)classLoadCurrent).getURLs())
      urls.add(url);
    for(URL url:urls)
      log.debug(url.toString());
    return new URLClassLoader(
      urls.toArray(new URL[urls.size()])
    );
  }
  /*=======================================================
   
  =======================================================*/
  public List<CompileUnit>createCompileUnit(String source,String className){
    CompileUnit compileUnit=new CompileUnit(
      source,
      classNameToFileName(className,Kind.SOURCE),
      Kind.SOURCE
    );
    List<CompileUnit>list=new ArrayList<Compile.CompileUnit>();
    
    list.add(compileUnit);
    return list;
  }
  /*=======================================================
   
  =======================================================*/
  private String classNameToFileName(String className,Kind kind){
    log.debug(String.format("className: %s",className));
    return String.format("file:///%s.%s",
      className.replaceAll("\\.","/"),
      kind==Kind.SOURCE?"java":"class"
    );
  }
  /*=======================================================
   
  =======================================================*/
  private String fileNameToClassName(String fileName){
    log.debug(String.format("fileName: %s",fileName));
    return fileName.substring(0)
      .replaceAll("\\/",".")
      .replaceAll("\\.class$","")
      .replaceAll("^(file\\:)(.*)","$2")
      .replaceAll("^[\\.]{1,}(.*)","$1");
  }
  /*=======================================================
   
  =======================================================*/
  private class FileManager extends EclipseFileManager implements Serializable{
    private static final long serialVersionUID=1L;
    public FileManager(Locale locale, Charset charset){
      super(locale,charset);
    }
    public ClassLoader getClassLoader(Location location){
      log.debug(String.format("class loader location: %s",location.getName()));
      return classLoadCompile;
    }
    public int isSupportedOption(String option){
      throw new RuntimeException("IMPLEMENT");
    }
    public boolean handleOption(String current,Iterator<String> remaining){
      log.debug(String.format("option: %s",current));
      return true;
    }
    public boolean hasLocation(Location location){
      log.debug(String.format("has location: %s",location.getName()));
      if("ANNOTATION_PROCESSOR_PATH".equals(location.getName()))
        return false;    
      return true;
    }
    public JavaFileObject getJavaFileForOutput(Location location,String className,Kind kind,FileObject sibling) throws IOException{
      CompileUnit compileUnit=new CompileUnit(
        "",
        classNameToFileName(className,kind),
        kind
      );
      
      return compileUnit;
    }
    public Iterable<? extends File> getLocation(Location location){
      if(!location.equals(StandardLocation.CLASS_PATH))
        return super.getLocation(location);
      
      List<File>files=new ArrayList<File>();
      URLClassLoader urlClassLoader=(URLClassLoader)classLoadCompile;
      
      for(URL url:urlClassLoader.getURLs()){
        files.add(new File(url.getPath()));
      }
      return files;
    }
    public Iterable<JavaFileObject> list(Location location,String packageName,Set<Kind> kinds,boolean recurse) throws IOException{
      throw new RuntimeException("IMPLEMENT");
    }
    public String inferBinaryName(Location location,JavaFileObject file){
      throw new RuntimeException("IMPLEMENT");
    }
    public boolean isSameFile(FileObject a,FileObject b){
      throw new RuntimeException("IMPLEMENT");
    }
    public JavaFileObject getJavaFileForInput(Location location,String className,Kind kind) throws IOException{
      throw new RuntimeException("IMPLEMENT");
    }
    public FileObject getFileForInput(Location location,String packageName,String relativeName) throws IOException{
      throw new RuntimeException("IMPLEMENT");
    }
    public FileObject getFileForOutput(Location location,String packageName,String relativeName,FileObject sibling) throws IOException{
      throw new RuntimeException("IMPLEMENT");
    }
    public void flush()throws IOException{}
    public void close() throws IOException{
      throw new RuntimeException("IMPLEMENT");
    }
  }
  /*=======================================================
   
  =======================================================*/
  private class CDiagnosticListener implements DiagnosticListener,Serializable{
    private static final long serialVersionUID=1L;
    public void report(Diagnostic diagnostic){}
  }
}
Comment 8 Stephan Herrmann CLA 2015-07-15 16:39:17 EDT
(In reply to Ricardo Wolosker from comment #6)
> Esse trecho de código impede a customização do StandardJavaFileManager,
> impondo o uso da componente EclipseFileManager. Para completar todas as API
> do classPath, é necessário override este método

(In reply to Ricardo Wolosker from comment #7)
> Consegui resolver com essa classe:

Sorry, my knowledge of Portuguese isn't quite up to the task :)
Comment 9 Stephan Herrmann CLA 2015-07-18 07:29:27 EDT
(In reply to Stephan Herrmann from comment #8)
> (In reply to Ricardo Wolosker from comment #6)
> > Esse trecho de código impede a customização do StandardJavaFileManager,
> > impondo o uso da componente EclipseFileManager. Para completar todas as API
> > do classPath, é necessário override este método
> 
> (In reply to Ricardo Wolosker from comment #7)
> > Consegui resolver com essa classe:
> 
> Sorry, my knowledge of Portuguese isn't quite up to the task :)

ping
Comment 10 Ricardo Wolosker CLA 2015-07-18 13:06:40 EDT
pong. I could settle with the class left in the comments. :)
Comment 11 Stephan Herrmann CLA 2015-07-19 06:06:32 EDT
(In reply to Ricardo Wolosker from comment #10)
> pong. I could settle with the class left in the comments. :)

I take this as saying there's no need for action in JDT.
Comment 12 Manoj N Palat CLA 2015-08-04 00:58:14 EDT
Verified for Eclipse Neon 4.6 M1 Build id: I20150803-2000