private static void flushPreference(String optionName, IEclipsePreferences node) { try { node.flush(); } catch (BackingStoreException e) { AptPlugin.log(e, "Failed to save preference: " + optionName); // $NON-NLS-1$ } }
/** * Set all the processor options in one call. This will delete any options that are not passed in, * so callers who do not wish to destroy pre-existing options should use addProcessorOption() * instead. * * @param options a map of keys to values. The keys should not include any automatic options (@see * #isAutomaticProcessorOption(String)), and the "-A" should not be included. That is, to * perform the equivalent of the apt command line "-Afoo=bar", use the key "foo" and the value * "bar". Keys cannot contain spaces; values can contain anything at all. Keys cannot be null, * but values can be. */ public static void setProcessorOptions(Map<String, String> options, IJavaProject jproj) { IScopeContext context = (null != jproj) ? new ProjectScope(jproj.getProject()) : InstanceScope.INSTANCE; // TODO: this call is needed only for backwards compatibility with // settings files previous to 2005.11.13. At some point it should be // removed. removeOldStyleSettings(context); IEclipsePreferences node = context.getNode( AptPlugin.PLUGIN_ID + "/" + //$NON-NLS-1$ AptPreferenceConstants.APT_PROCESSOROPTIONS); try { node.clear(); for (Entry<String, String> option : options.entrySet()) { String nonNullVal = option.getValue() == null ? AptPreferenceConstants.APT_NULLVALUE : option.getValue(); node.put(option.getKey(), nonNullVal); } node.flush(); } catch (BackingStoreException e) { AptPlugin.log(e, "Unable to save annotation processor options"); // $NON-NLS-1$ } }
/** * Turn annotation processing on or off for this project. * * <p>Prior to Eclipse 3.3, this affected the org.eclipse.jdt.apt.aptEnabled setting. In Eclipse * 3.3, it affects the org.eclipse.jdt.core.compiler.processingEnabled setting; the older setting * is still set (and read) in order to preserve backward compatibility. * * @param jproject an IJavaProject, or null to set workspace preferences. * @param enabled */ public static void setEnabled(IJavaProject jproject, boolean enabled) { if (jproject == null && enabled == true) { IllegalArgumentException e = new IllegalArgumentException(); IStatus status = AptPlugin.createWarningStatus( e, "Illegal attempt to enable annotation processing workspace-wide"); // $NON-NLS-1$ AptPlugin.log(status); throw e; } setString( jproject, AptPreferenceConstants.APT_PROCESSANNOTATIONS, enabled ? AptPreferenceConstants.ENABLED : AptPreferenceConstants.DISABLED); // backward compatibility: also save old setting setBoolean(jproject, AptPreferenceConstants.APT_ENABLED, enabled); }
/** * Flush unsaved preferences and perform any other config-related shutdown. This is called once, * from AptPlugin.shutdown(). */ public static void dispose() { try { InstanceScope.INSTANCE.getNode(AptPlugin.PLUGIN_ID).flush(); } catch (BackingStoreException e) { // log failure and continue AptPlugin.log(e, "Couldn't flush preferences to disk"); // $NON-NLS-1$ } }
// We need this as a separate method, as we'll put dependent projects' output // on the classpath private static void addProjectClasspath( IWorkspaceRoot root, IJavaProject otherJavaProject, Set<IJavaProject> projectsProcessed, Set<String> classpath) { // Check for cycles. If we've already seen this project, // no need to go any further. if (projectsProcessed.contains(otherJavaProject)) { return; } projectsProcessed.add(otherJavaProject); try { // Add the output directory first as a binary entry for other projects IPath binPath = otherJavaProject.getOutputLocation(); IResource binPathResource = root.findMember(binPath); String binDirString; if (binPathResource != null) { binDirString = root.findMember(binPath).getLocation().toOSString(); } else { binDirString = binPath.toOSString(); } classpath.add(binDirString); // Now the rest of the classpath IClasspathEntry[] classpathEntries = otherJavaProject.getResolvedClasspath(true); for (IClasspathEntry entry : classpathEntries) { if (entry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) { IPath cpPath = entry.getPath(); IResource res = root.findMember(cpPath); // If res is null, the path is absolute (it's an external jar) if (res == null) { classpath.add(cpPath.toOSString()); } else { // It's relative classpath.add(res.getLocation().toOSString()); } } else if (entry.getEntryKind() == IClasspathEntry.CPE_PROJECT) { IPath otherProjectPath = entry.getPath(); IProject otherProject = root.getProject(otherProjectPath.segment(0)); IJavaProject yetAnotherJavaProject = JavaCore.create(otherProject); if (yetAnotherJavaProject != null) { addProjectClasspath(root, yetAnotherJavaProject, projectsProcessed, classpath); } } // Ignore source types } } catch (JavaModelException jme) { AptPlugin.log( jme, "Failed to get the classpath for the following project: " + otherJavaProject); //$NON-NLS-1$ } }
private static void setBoolean(IJavaProject jproject, String optionName, boolean value) { IScopeContext context = (null != jproject) ? new ProjectScope(jproject.getProject()) : InstanceScope.INSTANCE; IEclipsePreferences node = context.getNode(AptPlugin.PLUGIN_ID); // get old val as a String, so it can be null if setting doesn't exist yet String oldValue = node.get(optionName, null); node.putBoolean(optionName, value); if (jproject != null && oldValue == null || (value != Boolean.parseBoolean(oldValue))) { AptProject aproj = AptPlugin.getAptProject(jproject); aproj.preferenceChanged(optionName); } flushPreference(optionName, node); }
/** * Set the org.eclipse.jdt.core.compiler.processAnnotations setting. In Eclipse 3.3, this value * replaces org.eclipse.jdt.apt.aptEnabled, but we continue to set both values in order to ensure * backward compatibility with prior versions. the aptEnabled setting. * * @param enable */ private void setJDTProcessAnnotationsSetting(boolean enable) { IScopeContext context = (null != fJProj) ? new ProjectScope(fJProj.getProject()) : InstanceScope.INSTANCE; IEclipsePreferences node = context.getNode(JavaCore.PLUGIN_ID); final String value = enable ? AptPreferenceConstants.ENABLED : AptPreferenceConstants.DISABLED; node.put(AptPreferenceConstants.APT_PROCESSANNOTATIONS, value); try { node.flush(); } catch (BackingStoreException e) { AptPlugin.log( e, "Failed to save preference: " + AptPreferenceConstants.APT_PROCESSANNOTATIONS); // $NON-NLS-1$ } }
private static void setString(IJavaProject jproject, String optionName, String value) { IScopeContext context = (null != jproject) ? new ProjectScope(jproject.getProject()) : InstanceScope.INSTANCE; IEclipsePreferences node; if (AptPreferenceConstants.APT_PROCESSANNOTATIONS.equals(optionName)) { node = context.getNode(JavaCore.PLUGIN_ID); } else { node = context.getNode(AptPlugin.PLUGIN_ID); } String oldValue = node.get(optionName, null); node.put(optionName, value); if (jproject != null && !value.equals(oldValue)) { AptProject aproj = AptPlugin.getAptProject(jproject); aproj.preferenceChanged(optionName); } flushPreference(optionName, node); }
/** * Get the options that are presented to annotation processors by the * AnnotationProcessorEnvironment. The -A and = are stripped out, so (key, value) is the * equivalent of -Akey=value. * * <p>This method differs from getProcessorOptions in that the options returned by this method do * NOT include any programmatically set options. This method returns only the options that are * persisted to the preference store and that are displayed in the configuration GUI. * * @param jproj a project, or null to query the workspace-wide setting. If jproj is not null, but * the project has no per-project settings, this method will fall back to the workspace-wide * settings. * @return a mutable, possibly empty, map of (key, value) pairs. The value part of a pair may be * null (equivalent to "-Akey"). The value part can contain spaces, if it is quoted: * -Afoo="bar baz". */ public static Map<String, String> getRawProcessorOptions(IJavaProject jproj) { Map<String, String> options = new HashMap<String, String>(); // TODO: this code is needed only for backwards compatibility with // settings files previous to 2005.11.13. At some point it should be // removed. // If an old-style setting exists, add it into the mix for backward // compatibility. options.putAll(getOldStyleRawProcessorOptions(jproj)); // Fall back from project to workspace scope on an all-or-nothing basis, // not value by value. (Never fall back to default scope; there are no // default processor options.) We can't use IPreferencesService for this // as we would normally do, because we don't know the names of the keys. IScopeContext[] contexts; if (jproj != null) { contexts = new IScopeContext[] {new ProjectScope(jproj.getProject()), InstanceScope.INSTANCE}; } else { contexts = new IScopeContext[] {InstanceScope.INSTANCE}; } for (IScopeContext context : contexts) { IEclipsePreferences prefs = context.getNode(AptPlugin.PLUGIN_ID); try { if (prefs.childrenNames().length > 0) { IEclipsePreferences procOptionsNode = context.getNode( AptPlugin.PLUGIN_ID + "/" + AptPreferenceConstants.APT_PROCESSOROPTIONS); // $NON-NLS-1$ if (procOptionsNode != null) { for (String key : procOptionsNode.keys()) { String nonNullVal = procOptionsNode.get(key, null); String val = AptPreferenceConstants.APT_NULLVALUE.equals(nonNullVal) ? null : nonNullVal; options.put(key, val); } break; } } } catch (BackingStoreException e) { AptPlugin.log(e, "Unable to load annotation processor options"); // $NON-NLS-1$ } } return options; }
/** * Remove an option from the list of processor options. * * @param jproj a project, or null to remove the option workspace-wide. * @param key must be a nonempty string. It should only include the key; that is, it should not * start with "-A". */ public static void removeProcessorOption(IJavaProject jproj, String key) { if (key == null || key.length() < 1) { throw new IllegalArgumentException(); } IScopeContext context = (null != jproj) ? new ProjectScope(jproj.getProject()) : InstanceScope.INSTANCE; IEclipsePreferences node = context.getNode( AptPlugin.PLUGIN_ID + "/" + //$NON-NLS-1$ AptPreferenceConstants.APT_PROCESSOROPTIONS); node.remove(key); try { node.flush(); } catch (BackingStoreException e) { AptPlugin.log(e, "Unable to save annotation processor option" + key); // $NON-NLS-1$ } }
/** * Get the options that are presented to annotation processors by the * AnnotationProcessorEnvironment. Options are key/value pairs which are set in the project * properties. * * <p>Option values can begin with a percent-delimited token representing a classpath variable or * one of several predefined values. The token must either be followed by a path delimiter, or be * the entire value. Such tokens will be replaced with their resolved value. The predefined values * are <code>%ROOT%</code>, which is replaced by the absolute pathname of the workspace root * directory, and <code>%PROJECT.DIR%</code>, which will be replaced by the absolute pathname of * the project root directory. For example, a value of <code> * %ECLIPSE_HOME%/configuration/config.ini</code> might be resolved to <code> * d:/eclipse/configuration/config.ini</code>. * * <p>This method returns some options which are set programmatically but are not directly * editable, are not displayed in the configuration GUI, and are not persisted to the preference * store. This is meant to emulate the behavior of Sun's apt command-line tool, which passes most * of its command line options to the processor environment. The programmatically set options are: * <code>-classpath</code> [set to Java build path] <code>-sourcepath</code> [set to Java source * path] <code>-s</code> [set to generated src dir] <code>-d</code> [set to binary output dir] * <code>-target</code> [set to compiler target version] <code>-source</code> [set to compiler * source version] * * <p>There are some slight differences between the options returned by this method and the * options returned from this implementation of @see AnnotationProcessorEnvironment#getOptions(). * First, that method returns additional options which are only meaningful during a build, such as * <code>phase</code>. Second, that method also adds alternate encodings of each option, to be * compatible with a bug in Sun's apt implementation: specifically, for each option key="k", * value="v", an additional option is created with key="-Ak=v", value=null. This includes the * user-created options, but does not include the programmatically defined options listed above. * * @param jproj a project, or null to query the workspace-wide setting. * @return a mutable, possibly empty, map of (key, value) pairs. The value part of a pair may be * null (equivalent to "-Akey" on the Sun apt command line). The value part may contain * spaces. */ public static Map<String, String> getProcessorOptions(IJavaProject jproj) { Map<String, String> rawOptions = getRawProcessorOptions(jproj); // map is large enough to also include the programmatically generated options Map<String, String> options = new HashMap<String, String>(rawOptions.size() + 6); // Resolve path metavariables like %ROOT% for (Map.Entry<String, String> entry : rawOptions.entrySet()) { String resolvedValue = resolveVarPath(jproj, entry.getValue()); String value = (resolvedValue == null) ? entry.getValue() : resolvedValue; options.put(entry.getKey(), value); } if (jproj == null) { // there are no programmatically set options at the workspace level return options; } IWorkspaceRoot root = jproj.getProject().getWorkspace().getRoot(); // Add sourcepath and classpath variables try { IClasspathEntry[] classpathEntries = jproj.getResolvedClasspath(true); Set<String> classpath = new LinkedHashSet<String>(); Set<String> sourcepath = new LinkedHashSet<String>(); // For projects on the classpath, loops can exist; need to make sure we // don't loop forever Set<IJavaProject> projectsProcessed = new HashSet<IJavaProject>(); projectsProcessed.add(jproj); for (IClasspathEntry entry : classpathEntries) { int kind = entry.getEntryKind(); if (kind == IClasspathEntry.CPE_LIBRARY) { IPath cpPath = entry.getPath(); IResource res = root.findMember(cpPath); // If res is null, the path is absolute (it's an external jar) if (res == null) { classpath.add(cpPath.toOSString()); } else { // It's relative classpath.add(res.getLocation().toOSString()); } } else if (kind == IClasspathEntry.CPE_SOURCE) { IResource res = root.findMember(entry.getPath()); if (res == null) { continue; } IPath srcPath = res.getLocation(); if (srcPath == null) { continue; } sourcepath.add(srcPath.toOSString()); } else if (kind == IClasspathEntry.CPE_PROJECT) { // Add the dependent project's build path and classpath to ours IPath otherProjectPath = entry.getPath(); IProject otherProject = root.getProject(otherProjectPath.segment(0)); // Note: JavaCore.create() is safe, even if the project is null -- // in that case, we get null back IJavaProject otherJavaProject = JavaCore.create(otherProject); // If it doesn't exist, ignore it if (otherJavaProject != null && otherJavaProject.isOpen()) { addProjectClasspath(root, otherJavaProject, projectsProcessed, classpath); } } } // if you add options here, also add them in isAutomaticProcessorOption(), // and document them in docs/reference/automatic_processor_options.html. // Classpath and sourcepath options.put("-classpath", convertPathCollectionToString(classpath)); // $NON-NLS-1$ options.put("-sourcepath", convertPathCollectionToString(sourcepath)); // $NON-NLS-1$ // Get absolute path for generated source dir IFolder genSrcDir = jproj.getProject().getFolder(getGenSrcDir(jproj)); String genSrcDirString = genSrcDir.getRawLocation().toOSString(); options.put("-s", genSrcDirString); // $NON-NLS-1$ // Absolute path for bin dir as well IPath binPath = jproj.getOutputLocation(); IResource binPathResource = root.findMember(binPath); String binDirString; if (binPathResource != null) { binDirString = root.findMember(binPath).getLocation().toOSString(); } else { binDirString = binPath.toOSString(); } options.put("-d", binDirString); // $NON-NLS-1$ String target = jproj.getOption(JavaCore.COMPILER_CODEGEN_TARGET_PLATFORM, true); options.put("-target", target); // $NON-NLS-1$ String source = jproj.getOption(JavaCore.COMPILER_SOURCE, true); options.put("-source", source); // $NON-NLS-1$ } catch (JavaModelException jme) { AptPlugin.log(jme, "Could not get the classpath for project: " + jproj); // $NON-NLS-1$ } return options; }