upgrading to spring 5.0.7.RELEASE is causing issues with parseStringValue - java

We have a Java program and a 3rd party API that stay in sync with Spring between the two.
After upgrading from 4.2.5.RELEASE to 5.0.7.RELEASE
I'm seeing the following error in one of the files:
The method parseStringValue(String, Properties, HashSet) is
undefined for the type
NestedPropertyPlaceholderConfigurer NestedPropertyPlaceholderConfigurer.java
I attempted to use this import instead PropertyPlaceholderHelper but then I seemed to be going down a rabbit hole of errors and I wasn't even sure that was the right approach.
This is the page of code in it's entirety (minus some redacted info):
package redacted.primavera.common.spring;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.io.Resource;
/**
* Extends the PropertyPlaceholderConfigurer to implement nested resource
* location placeholders. Properties from the top-level resources may be
* used to define nested resources.
*
* #author redacted
*
*/
public class NestedPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements ApplicationContextAware {
private ApplicationContext applicationContext;
private Resource[] topLocations;
private List<String> nestedLocations;
/*
* Post-process the bean factory. Add the nested resource locations to the
* top-level resource locations before processing.
*
* (non-Javadoc)
* #see org.springframework.beans.factory.config.PropertyResourceConfigurer#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
*/
#Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
try {
Properties props = mergeProperties();
List<Resource> merged = new ArrayList<Resource>();
for (int i = 0; i < topLocations.length; i++) {
merged.add(topLocations[i]);
}
for (String nestedLocation : this.nestedLocations) {
String location = parseStringValue(nestedLocation.replaceAll("#\\{", "\\${"), props, new HashSet<String>());
if (location != null) {
Resource[] resources = this.applicationContext.getResources(location);
for (int i = 0; i < resources.length; i++) {
Resource resource = resources[i];
if (!merged.contains(resource)) {
merged.add(resource);
}
}
}
}
setLocations(merged.toArray(new Resource[merged.size()]));
}
catch (Exception e) {
throw new RuntimeException("", e);
}
super.postProcessBeanFactory(beanFactory);
}
/*
* (non-Javadoc)
* #see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/*
* Set resource locations and save a local copy.
*
* (non-Javadoc)
* #see org.springframework.core.io.support.PropertiesLoaderSupport#setLocations(org.springframework.core.io.Resource[])
*/
#Override
public void setLocations(Resource[] locations) {
this.topLocations = new Resource[locations.length];
System.arraycopy(locations, 0, this.topLocations, 0, locations.length);
super.setLocations(locations);
}
/**
* Set the nested resource locations.
* #param nestedLocations
*/
public void setNestedLocations(List<String> nestedLocations) {
this.nestedLocations = nestedLocations;
}
}

As you can see in the javadoc of version 4.x this method was deprecated and removed in version 5.x.
parseStringValue(String strVal, Properties props, Set visitedPlaceholders)
Deprecated.
as of Spring 3.0, in favor of using resolvePlaceholder(java.lang.String, java.util.Properties, int) with PropertyPlaceholderHelper. Only retained for compatibility with Spring 2.5 extensions.
So you have to refactor you code and use PropertyPlaceholderHelper

parseStringValue(String strVal, Properties props, Set visitedPlaceholders)
was deprecated.
As Jens suggested here is my refactored code changes to fix the compile issues:
Added an import:
import org.springframework.util.PropertyPlaceholderHelper;
Method variable:
PropertyPlaceholderHelper pph = new PropertyPlaceholderHelper(DEFAULT_PLACEHOLDER_PREFIX, DEFAULT_PLACEHOLDER_SUFFIX);
3. Replaced method call:
String location = pph.replacePlaceholders(nestedLocation.replaceAll("#\\{", "\\${"), props);

Related

Spring MVC: UI-Testing with Test WebApplicationContext and embedded Jetty

tldr; How do I deploy from WebApplicationContext in embedded jetty for a simple automatic test case?
What I have:
A spring application (not spring boot) that uses annotation configuration (no web.xml) and is - for production - build (with gradle) to an ear and deployed on wildfly.
What I ultimately want to do:
Have self-contained (in the applications test package) ui-tests, that can easily be executed (without building and deploying) like any of the other unit or integration tests.
What I have done so far:
The easy part: Setup the actual tests with Selenium WebDriver
The hard part: Start an embedded Jetty with a test WebApplicationContext
My code for the embedded Jetty (yes, I will do some refactoring when I get it running):
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.eclipse.jetty.apache.jsp.JettyJasperInitializer;
import org.eclipse.jetty.jsp.JettyJspServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.HashSessionIdManager;
import org.eclipse.jetty.server.session.HashSessionManager;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.resource.Resource;
import org.springframework.security.web.FilterChainProxy;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
public class JettyServerFactory {
private Server server = null;
public Server start(WebApplicationContext context) throws Exception {
if (server == null) {
this.server = new Server(9090);
setupServer(context);
server.start();
//server.join();
}
return server;
}
public void stop() throws Exception {
if (server != null) {
server.stop();
}
}
private void setupServer(WebApplicationContext context) throws Exception {
final ServletContextHandler contextHandler = new ServletContextHandler();
// Since this is a ServletContextHandler we must manually configure JSP support.
enableEmbeddedJspSupport(contextHandler);
// Spring Security
enableSpringSecurity(contextHandler, context);
/*
// TODO: Does not seem to have any effect
// Set reference to actual Spring ApplicationContext
ServletContext servletContext = contextHandler.getServletContext();
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, context);
*/
// Set resource base folder
contextHandler.setBaseResource(getResourceBase());
// Add DispatcherServlet to context
final ServletHolder servletHolder = new ServletHolder("default", new DispatcherServlet(context));
servletHolder.setInitParameter("dirAllowed", "true");
contextHandler.setContextPath("/oauth");
contextHandler.addServlet(servletHolder, "/");
// Add context to server
server.setHandler(contextHandler);
}
private Resource getResourceBase() {
File file = new File("src/website/application.war");
//servletHolder.setInitParameter("resourceBase", getWebRootResourceUri().toASCIIString());
final Resource base = Resource.newResource(file);
return base;
}
/**
* Apply existing securityFilterChain to context
*
* #param contextHandler
* #param context
*/
private void enableSpringSecurity(ServletContextHandler contextHandler, WebApplicationContext context) {
FilterChainProxy filter = (FilterChainProxy) context.getBean("springSecurityFilterChain");
FilterHolder filterHolder = new FilterHolder(filter);
contextHandler.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class));
server.setSessionIdManager(new HashSessionIdManager());
HashSessionManager manager = new HashSessionManager();
SessionHandler sessions = new SessionHandler(manager);
contextHandler.setHandler(sessions);
}
/**
* Setup JSP Support for ServletContextHandlers.
* <p>
* NOTE: This is not required or appropriate if using a WebAppContext.
* </p>
*
* #param servletContextHandler the ServletContextHandler to configure
* #throws IOException if unable to configure
*/
private void enableEmbeddedJspSupport(ServletContextHandler servletContextHandler) throws IOException {
// Establish Scratch directory for the servlet context (used by JSP compilation)
File tempDir = new File(System.getProperty("java.io.tmpdir"));
File scratchDir = new File(tempDir.toString(), "embedded-jetty-jsp");
if (!scratchDir.exists()) {
if (!scratchDir.mkdirs()) {
throw new IOException("Unable to create scratch directory: " + scratchDir);
}
}
servletContextHandler.setAttribute("javax.servlet.context.tempdir", scratchDir);
// Set Classloader of Context to be sane (needed for JSTL)
// JSP requires a non-System classloader, this simply wraps the
// embedded System classloader in a way that makes it suitable
// for JSP to use
ClassLoader jspClassLoader = new URLClassLoader(new URL[0], this.getClass().getClassLoader());
servletContextHandler.setClassLoader(jspClassLoader);
// Manually call JettyJasperInitializer on context startup
servletContextHandler.addBean(new JspStarter(servletContextHandler));
// Create / Register JSP Servlet (must be named "jsp" per spec)
ServletHolder holderJsp = new ServletHolder("jsp", JettyJspServlet.class);
holderJsp.setInitOrder(0);
holderJsp.setInitParameter("logVerbosityLevel", "DEBUG");
holderJsp.setInitParameter("fork", "false");
holderJsp.setInitParameter("xpoweredBy", "false");
holderJsp.setInitParameter("compilerTargetVM", "1.8");
holderJsp.setInitParameter("compilerSourceVM", "1.8");
holderJsp.setInitParameter("keepgenerated", "true");
servletContextHandler.addServlet(holderJsp, "*.jsp");
}
/**
* JspStarter for embedded ServletContextHandlers
*
* This is added as a bean that is a jetty LifeCycle on the ServletContextHandler. This bean's doStart method will
* be called as the ServletContextHandler starts, and will call the ServletContainerInitializer for the jsp engine.
*
*/
public static class JspStarter extends AbstractLifeCycle
implements ServletContextHandler.ServletContainerInitializerCaller {
JettyJasperInitializer sci;
ServletContextHandler context;
public JspStarter(ServletContextHandler context) {
this.sci = new JettyJasperInitializer();
this.context = context;
this.context.setAttribute("org.apache.tomcat.JarScanner", new StandardJarScanner());
}
#Override
protected void doStart() throws Exception {
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(context.getClassLoader());
try {
sci.onStartup(null, context.getServletContext());
super.doStart();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
}
private URI getWebRootResourceUri() throws FileNotFoundException, URISyntaxException, MalformedURLException {
String WEBROOT_INDEX = "/application.war/";
URL indexUri = this.getClass().getResource(WEBROOT_INDEX);
if (indexUri == null) {
throw new FileNotFoundException("Unable to find resource " + WEBROOT_INDEX);
}
File file = new File("src/website/application.war");
System.out.println(indexUri.toURI());
System.out.println(file.toURI());
System.out.println(file.getAbsolutePath());
return file.toURI();
}
}
The WebApplicationContext for the test case is simply provided somewhat like this:
...
#WebAppConfiguration
public class ATestClass {
#Autowired
WebApplicationContext context;
...
#Before
public void setupTest() throws Exception {
new JettyServerFactory().start(context);
...
}
...
...
Location of the Resource Base:
Resource placement in the project structure
All static resources like css, js and images are in themes
What does work:
Controllers are hit on requests
Spring Security is active
JSPs are found and rendered (thanks to https://github.com/jetty-project/embedded-jetty-jsp)
What does not work:
All other static resources are missing (css, js, images, etc.). Basically everything from themes
So, what are my questions:
How can I make the missing static resources available?
Is there a completely different/better approach to achieve my ultimate goal? The way, to what I have now, was quite rocky and I'm not sure the missing static content is the last of my problems.
I'm happy to provide additional information/code. But, since this is an actual product, I have some limits on that.
Edits:
Picture of the resource structure
Mind that application.war is just a folder, not actually a war
Resource Config
#EnableWebMvc
#Configuration
public class AppWebMvcConfiguration implements WebMvcConfigurer {
...
#Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.jsp("/WEB-INF/jsp/", ".jsp");
}
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
boolean developmentMode = configuration.getBooleanFromNewconfig(false, "oauth2.developmentMode");
if (USE_VERSIONED_RESOURCES) {
registry.addResourceHandler("/themes/**")
.addResourceLocations("/themes/")
.setCacheControl(CacheControl.maxAge(365, TimeUnit.DAYS))
.resourceChain(developmentMode ? false : true)
.addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"))
.addTransformer(new CssLinkResourceTransformer());
} else {
registry.addResourceHandler("/themes/**")
.addResourceLocations("/themes/")
.setCacheControl(CacheControl.noCache());
}
}
...
}
Which case is used for the ResourceHandler doesn't matter. Neither works.

How to write a proper unit test for Elasticsearch in Java

Overview:
I'm totally new to Elastic search testing and I'm gonna add proper unit tests. The project compatibilities are as follow:
Java 8
Elasticsearch 6.2.4
Project uses low level rest client for fetching data from ES
More info about ES configurations is as follow:
import static java.net.InetAddress.getByName;
import static java.util.Arrays.stream;
import java.net.UnknownHostException;
import java.util.Map;
import java.util.Objects;
import javax.inject.Inject;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import au.com.api.util.RestClientUtil;
import lombok.extern.slf4j.Slf4j;
#Slf4j
#Configuration
public class ElasticConfiguration implements InitializingBean{
#Value(value = "${elasticsearch.hosts}")
private String[] hosts;
#Value(value = "${elasticsearch.httpPort}")
private int httpPort;
#Value(value = "${elasticsearch.tcpPort}")
private int tcpPort;
#Value(value = "${elasticsearch.clusterName}")
private String clusterName;
#Inject
private RestClientUtil client;
#Bean
public RestHighLevelClient restHighClient() {
return new RestHighLevelClient(RestClient.builder(httpHosts()));
}
#Bean
#Deprecated
public RestClient restClient() {
return RestClient.builder(httpHosts()).build();
}
/**
* #return TransportClient
* #throws UnknownHostException
*/
#SuppressWarnings("resource")
#Bean
public TransportClient transportClient() throws UnknownHostException{
Settings settings = Settings.builder()
.put("cluster.name", clusterName).build();
return new PreBuiltTransportClient(settings).addTransportAddresses(transportAddresses());
}
#Override
public void afterPropertiesSet() throws Exception {
log.debug("loading search templates...");
try {
for (Map.Entry<String, String> entry : Constants.SEARCH_TEMPLATE_MAP.entrySet()) {
client.putInlineSearchTemplateToElasticsearch(entry.getKey(), entry.getValue());
}
} catch (Exception e) {
log.error("Exception has occurred in putting search templates into ES.", e);
}
}
private HttpHost[] httpHosts() {
return stream(hosts).map(h -> new HttpHost(h, httpPort, "http")).toArray(HttpHost[]::new);
}
private TransportAddress[] transportAddresses() throws UnknownHostException {
TransportAddress[] transportAddresses = stream(hosts).map(h -> {
try {
return new TransportAddress(getByName(h), tcpPort);
} catch (UnknownHostException e) {
log.error("Exception has occurred in creating ES TransportAddress. host: '{}', tcpPort: '{}'", h, tcpPort, e);
}
return null;
}).filter(Objects::nonNull).toArray(TransportAddress[]::new);
if (transportAddresses.length == 0) {
throw new UnknownHostException();
}
return transportAddresses;
}
}
Issue:
I don't know how to Mock ES or how to test ES without running an standalone ES on my machine. Please use the following class as an example and let me know how could I write a testcase (unit test not integration) for getSearchResponse method:
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.transport.NoNodeAvailableException;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.script.mustache.SearchTemplateRequestBuilder;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.aggregations.Aggregation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Repository;
#Slf4j
#Repository
#NoArgsConstructor
public abstract class NewBaseElasticsearchRepository {
#Autowired
protected NewIndexLocator newIndexLocator;
#Value(value = "${elasticsearch.client.timeout}")
private Long timeout;
#Autowired
protected TransportClient transportClient;
#Autowired
protected ThresholdService thresholdService;
#Autowired
protected MessageSource messageSource;
/**
* #param script the name of the script to be executed
* #param templateParams a map of the parameters to be sent to the script
* #param indexName the index to target (an empty indexName will search all indexes)
*
* #return a Search Response object containing details of the request results from Elasticsearch
*
* #throws NoNodeAvailableException thrown when the transport client cannot connect to any ES Nodes (or Coordinators)
* #throws Exception thrown for all other request errors such as parsing and non-connectivity related issues
*/
protected SearchResponse getSearchResponse(String script, Map<String, Object> templateParams, String... indexName) {
log.debug("transport client >> index name --> {}", Arrays.toString(indexName));
SearchResponse searchResponse;
try {
searchResponse = new SearchTemplateRequestBuilder(transportClient)
.setScript(script)
.setScriptType(ScriptType.STORED)
.setScriptParams(templateParams)
.setRequest(new SearchRequest(indexName))
.execute()
.actionGet(timeout)
.getResponse();
} catch (NoNodeAvailableException e) {
log.error(ELASTIC_SEARCH_EXCEPTION_NOT_FOUND, e.getMessage());
throw new ElasticSearchException(ELASTIC_SEARCH_EXCEPTION_NOT_FOUND);
} catch (Exception e) {
log.error(ELASTIC_SEARCH_EXCEPTION, e.getMessage());
throw new ElasticSearchException(ELASTIC_SEARCH_EXCEPTION);
}
log.debug("searchResponse ==> {}", searchResponse);
return searchResponse;
}
So, I would be grateful if you could have a look on the example class and share your genuine solutions with me here about how could I mock TransportClient and get a proper response from SearchResponse object.
Note:
I tried to use ESTestCase from org.elasticsearch.test:framework:6.2.4 but faced jar hell issue and could't resolve it. In the meantime, I could't find any proper docs related to that or Java ES unit testing, in general.

Extension of `MavenProjectWizard` possible?

What I want: I have an editor plug-in for my custom DSL. I want to offer the user to set up a new DSL project with a project wizard. Normally these projects are Maven projects, so I want to provide setting up the project directly as a Maven project. To do that I want to extend the class MavenProjectWizardin the package org.eclipse.m2e.core.ui.internal.wizards.MavenProjectWizard and then add another wizard page with the details regarding the DSL project.
What I have: This is my try to do it at the moment:
/*
* Copyright (c) 2017 RWTH Aachen. All rights reserved.
*
* http://www.se-rwth.de/
*/
package de.se_rwth.transformationeditor.wizard;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.m2e.core.ui.internal.wizards.MavenProjectWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.wizards.newresource.BasicNewResourceWizard;
import jline.internal.Log;
/**
* Offers a wizard to create a new Transformation project
*
* #author (last commit) $Philipp Nolte$
* #version $Revision$, $12.1.2017$
* #since 0.0.3
*/
#SuppressWarnings("restriction")
public class CDProjectWizard extends MavenProjectWizard{
protected CDWizardPageOne one;
protected WizardPage currentPage;
private IWorkbench workbench;
public CDProjectWizard() {
super();
}
/**
* #see org.eclipse.jface.wizard.IWizard#addPages()
*/
#Override
public void addPages() {
one = new CDWizardPageOne();
addPage(one);
super.addPages();
}
/**
* #see org.eclipse.ui.wizards.newresource.BasicNewProjectResourceWizard#init(org.eclipse.ui.IWorkbench,
* org.eclipse.jface.viewers.IStructuredSelection)
*/
#Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
super.init(workbench, selection);
this.workbench = workbench;
}
/**
* #see org.eclipse.jface.wizard.IWizard#getWindowTitle()
*/
#Override
public String getWindowTitle() {
return "New Class Diagram Transformation Project";
}
/**
* Creates a new Transformation project with the project name given in the
* wizard. Inside this project a new folder named "Transformations" is
* created. If a project with the same name already exists, an error window is
* shown. In addition to that, checks if user wants to create CD or MA xample
* files and creates them if wanted.
*
* #see org.eclipse.jface.wizard.IWizard#performFinish()
*/
#Override
public boolean performFinish() {
if (this.canFinish()) {
// Create new project
String projectName = this.one.getProjectNameText();
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
IProject project = root.getProject(projectName);
try {
if (!project.exists()) {
project.create(null);
}
else {
project.refreshLocal(IResource.DEPTH_INFINITE, null);
MessageDialog.openError(this.workbench.getActiveWorkbenchWindow().getShell(),
"Project creation error", "Project with this name already exists");
return false;
}
if (!project.isOpen()) {
project.open(null);
}
String transformationFolderName = "Transformations";
// Check subfolder name
if (!one.getRootFolderText().isEmpty()) {
transformationFolderName = one.getRootFolderText();
}
IFolder binFolder = project.getFolder(transformationFolderName);
if (!binFolder.exists()) {
one.createNewFolder(binFolder, false, true, null);
// Checks if user wants to create a CD example file
if (one.createCDExampleFile()) {
InputStream demoFileContents = null;
try {
// If the user wants to, an example file is created
URL url = new URL("platform:/plugin/cdtrans-editor/src/main/resources/exampleFiles/RefactorCDs");
InputStream inputStream = url.openConnection().getInputStream();
binFolder.getFile("RefactorCDs.cdtr").create(inputStream, true, null);
}
catch (IOException e) {
Log.error("TransProjectWizard: Error while creating Demo file", e);
MessageDialog.openError(this.workbench.getActiveWorkbenchWindow().getShell(),
"Example file creation error", "There was an error while creating the example file");
}
finally {
if (demoFileContents != null) {
try {
demoFileContents.close();
}
catch (IOException e) {
Log.error("TransProjectWizard: Error while closing file stream", e);
}
}
}
}
BasicNewResourceWizard.selectAndReveal(binFolder, this.workbench.getActiveWorkbenchWindow());
}
}
catch (CoreException e) {
Log.error("TransProjectWizard: Error while creating new Project", e);
}
}
return true;
}
}
But if I start this there is a runtime error if I try to open the wizard which says:
I already tried to export the plug-in and install it in a fresh Eclipse installation, where the m2e package is installed, but with the same result.
Any thoughts on how to fix it?

what does this Spring JSON endpoint break in Jboss/Tomcat?

what does this Spring JSON endpoint break in Jboss/Tomcat ? I tried to add this to an existing APPLICATION and It worked until I started refactoring the code and now the errors do not point to anything that is logical to me.
Here is my code a controller and Helper class to keep things clean.
Controller.Java
import java.io.IOException;
import java.util.Properties;
import javax.annotation.Nonnull;
import org.apache.commons.configuration.ConfigurationException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
#Controller
public class PropertiesDisplayController {
#Nonnull
private final PropertiesDisplayHelper propertiesHelper;
/**
* #param propertiesHelper
*/
#Nonnull
#Autowired
public PropertiesDisplayController(#Nonnull final PropertiesDisplayHelper propertiesHelper) {
super();
this.propertiesHelper = propertiesHelper;
}
#Nonnull
#RequestMapping("/localproperties")
public #ResponseBody Properties localProperties() throws ConfigurationException, IOException {
return propertiesHelper.getLocalProperties();
}
#Nonnull
#RequestMapping("/properties")
public #ResponseBody Properties applicationProperties() throws IOException,
ConfigurationException {
return propertiesHelper.getApplicationProperties();
}
}
this would be the Helper.java
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.TreeMap;
import javax.annotation.Nonnull;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
public class PropertiesDisplayHelper {
/** Static location of properties in for SSO */
private static String LOCAL_PROPERTIES_LOCATION =
"local.properties";
/** Static strings for masking the passwords and blank values */
private static String NOVALUE = "**NO VALUE**";
/** Static strings for masking the passwords and blank values */
private static String MASKED = "**MASKED**";
#Nonnull
public Properties getApplicationProperties() throws ConfigurationException {
final Properties properties = new Properties();
final Configuration configuration = AppConfiguration.Factory.getConfiguration();
// create a map of properties
final Iterator<?> propertyKeys = configuration.getKeys();
final Map<String, String> sortedProperties = new TreeMap<String, String>();
// loops the configurations and builds the properties
while (propertyKeys.hasNext()) {
final String key = propertyKeys.next().toString();
final String value = configuration.getProperty(key).toString();
sortedProperties.put(key, value);
}
properties.putAll(sortedProperties);
// output of the result
formatsPropertiesData(properties);
return properties;
}
#Nonnull
public Properties getLocalProperties() throws ConfigurationException, IOException {
FileInputStream fis = null;
final Properties properties = new Properties();
// imports file local.properties from specified location
// desinated when the update to openAM12
try {
fis = new FileInputStream(LOCAL_PROPERTIES_LOCATION);
properties.load(fis);
} finally {
// closes file input stream
IOUtils.closeQuietly(fis);
}
formatsPropertiesData(properties);
return properties;
}
void formatsPropertiesData(#Nonnull final Properties properties) {
for (final String key : properties.stringPropertyNames()) {
String value = properties.getProperty(key);
if (StringUtils.isEmpty(value)) {
value = NOVALUE;
} else if (key.endsWith("ssword")) {
value = MASKED;
} else {
value = StringEscapeUtils.escapeHtml(value);
}
// places data to k,v paired properties object
properties.put(key, value);
}
}
}
they set up a json display of the properties in application and from a file for logging. Yet now this no intrusive code seems to break my entire application build.
Here is the error from Jboss
20:33:41,559 ERROR [org.jboss.as.server] (DeploymentScanner-threads - 1) JBAS015870: Deploy of deployment "openam.war" was rolled back with the following failure message:
{"JBAS014671: Failed services" => {"jboss.deployment.unit.\"APPLICATION.war\".STRUCTURE" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"APPLICATION.war\".STRUCTURE: JBAS018733: Failed to process phase STRUCTURE of deployment \"APPLICATION.war\"
Caused by: org.jboss.as.server.deployment.DeploymentUnitProcessingException: JBAS018740: Failed to mount deployment content
Caused by: java.io.FileNotFoundException:APPLICATION.war (Access is denied)"}}
and the Errors from Tomcat
http://pastebin.com/PXdcpqvc
I am at a lost here and think there is something I just do not see.
A simple solution was at hand. The missing component was #Component annotation on the helper class.

Annotation processing for adding message attribute to existing JSR-303 annotations on fields

I have a data transfer object that's annotated with JSR-303 constraints like...
public class AssetOwnedDailyLocatableId implements Serializable, AssetOwned, HasOperatingDay, Locatable {
private static final long serialVersionUID = 1L;
#NotEmpty
#Size(min = 1, max = 30)
private String locationName;
#NotEmpty
private String operatingDay;
#NotEmpty
#Size(min = 1, max = 30)
private String assetOwner;
I am attempting to use Annotation Processing to enrich each JSR-303 constraint with a message attribute whose value would be equal to the constraint-name.class-name.member-name.
E.g., using the above, the final generated output for the locationName field's annotations would look like...
#NotEmpty(message="{NotEmpty.AssetOwnedDailyLocatableId.locationName}")
#Size(min = 1, max = 30, message="{Size.AssetOwnedDailyLocatableId.locationName}")
private String locationName;
Why? Because I want complete control over custom validation messaging. I have well over hundreds of data transfer objects that I would like to process with something like...
/**
* ViolationConstraint message processor. During compile time it scans all DTO
* classes that have <code>javax.validation.constrants.*</code> or
* <code>org.hibernate.validator.constraints.*</code>annotated
* fields, then enriches the annotation with a <code>message</code> attribute
* where its value will be <code>constraint-name.class-name.field-name</code>.
*
* #param <T>
* any JSR-303 annotation type
*
*/
#SupportedSourceVersion(SourceVersion.RELEASE_6)
#SupportedAnnotationTypes(value = { "javax.validation.constraints.*", "org.hibernate.validator.constraints.*" })
public class ValidationMessagesProcessor<T extends Annotation> extends AbstractProcessor {
private static final String JAVAX_PATH = "javax.validation.constraints.*";
private static final String HIBERNATE_PATH = "org.hibernate.validator.constraints/*";
private PackageUtil<T> util;
public ValidationMessagesProcessor() {
super();
util = new PackageUtil<T>();
}
/* (non-Javadoc)
* #see javax.annotation.processing.AbstractProcessor#process(java.util.Set, javax.annotation.processing.RoundEnvironment)
*/
#Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnvironment) {
if (!roundEnvironment.processingOver()) {
String message;
message = ValidationMessagesProcessor.class.getName() + " will begin processing now...";
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message);
try {
final List<Class<T>> annotationTypes = new ArrayList<Class<T>>();
final List<Class<T>> jxTypes = util.listMatchingClasses(JAVAX_PATH);
final List<Class<T>> hibTypes = util.listMatchingClasses(HIBERNATE_PATH);
annotationTypes.addAll(jxTypes);
annotationTypes.addAll(hibTypes);
for (final Element e : roundEnvironment.getRootElements()) {
// TODO Do the real work!
/*message = "... JSR-303 annotation '" + a.annotationType().getClass().getName() + "' found in "
+ e.getSimpleName();
processingEnv.getMessager().printMessage(Diagnostic.Kind.NOTE, message); */
}
} catch (final IOException ioe) {
message = "Failed to locate javax.validation.constraints or org.hibernate.validator.constraints classes on classpath!";
processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, message);
}
}
return true; // no further processing of this annotation type
}
}
I want to know if the above approach is feasible, or if I should try something else (that might be simpler). Furthermore, if it is feasible, some direction on what to implement within the //TODO section of the processor above. So far I've consulted...
http://today.java.net/pub/a/today/2008/04/10/source-code-analysis-using-java-6-compiler-apis.html#resources
http://blog.xebia.com/2009/07/21/testing-annotation-processors/
The drawbacks of annotation processing in Java?
Writing an annotation processor for maven-processor-plugin
How to use custom annotation processor with Maven 2?
Can I get from a TypeVariable or VariableElement to a list of Methods on the underlying class In an annotation processor at compile time
So I opted for authoring a utility based on Eclipse JDT.
Took me a while to hunt down all the dependent libs to make this work. For anyone else interested here's the Maven dependencies:
<!-- Validation API and Impl -->
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>${validation-api.version}</version>
</dependency>
<!-- Hibernate validator impl -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
<!-- Required to power classpath scanning for JSR-303 classes within JAR packages -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.framework.version}</version>
</dependency>
<!-- Required to employ all Eclipse JDT capabilities -->
<!-- This specific collection of artifact versions is known to work together -->
<!-- Take caution when upgrading versions! -->
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
<version>3.8.1.v20120502-0834</version>
</dependency>
<dependency>
<groupId>org.eclipse.tycho</groupId>
<artifactId>org.eclipse.osgi</artifactId>
<version>3.8.0.v20120430-1750</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.resources</artifactId>
<version>3.7.100.v20110510-0712</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
<version>3.7.0.v_B61</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.runtime</artifactId>
<version>3.7.0.v20110110</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.equinox.common</artifactId>
<version>3.6.0.v20110523</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.text</artifactId>
<version>3.5.100.v20110505-0800</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.jobs</artifactId>
<version>3.5.100.v20110404</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.core.contenttype</artifactId>
<version>3.4.100.v20110423-0524</version>
</dependency>
<dependency>
<groupId>org.jibx.config.3rdparty.org.eclipse</groupId>
<artifactId>org.eclipse.equinox.preferences</artifactId>
<version>3.4.0.v20110502</version>
</dependency>
I authored four classes one with main harness and the others a facade and utils.
The harness:
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.text.edits.MalformedTreeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spp.im.mui.commons.jdt.JDTFacade;
import org.spp.im.mui.commons.util.FileUtil;
import org.spp.im.mui.commons.util.PackageUtil;
import org.springframework.util.CollectionUtils;
/**
* A utility that scans all DTO classes that have
* <code>javax.validation.constrants.*</code> or
* <code>org.hibernate.validation.constraints.*</code> annotated fields, then
* enriches the annotation with a <code>message</code> attribute where its value
* will be <code>constraint-name.class-name.field-name</code>.
*
* #author cphillipson
* #param <T>
* any JSR-303 annotation type
*
*/
public class ConstraintMessageUtil<T extends Annotation> {
private static Logger log = LoggerFactory.getLogger(ConstraintMessageUtil.class);
private static final String JAVAX_PATH = "/javax/validation/constraints/*";
private static final String HIBERNATE_PATH = "/org/hibernate/validator/constraints/*";
private PackageUtil<T> util;
private JDTFacade<T> facade;
public ConstraintMessageUtil() {
util = new PackageUtil<T>();
facade = new JDTFacade<T>();
}
public void process(String sourcePath) throws Exception {
// step #1: build a set of JSR-303 constraint classes
final Set<Class<T>> annotationTypes = new HashSet<Class<T>>();
try {
final List<Class<T>> jxTypes = util.listMatchingClasses(JAVAX_PATH);
final List<Class<T>> hibTypes = util.listMatchingClasses(HIBERNATE_PATH);
annotationTypes.addAll(jxTypes);
annotationTypes.addAll(hibTypes);
// remove #Valid from the mix
annotationTypes.remove(Valid.class);
Assert.isTrue(!annotationTypes.contains(Valid.class));
} catch (final IOException ioe) {
}
// step #2: get all files recursively from source path
final Collection<File> allJavaSourceInDirectory = FileUtil.getAllJavaSourceInDirectory(new File(sourcePath),
true);
// step #3: filter files to just the ones that contain annotations
final List<File> annotatedSources = new ArrayList<File>();
if (!CollectionUtils.isEmpty(allJavaSourceInDirectory)) {
boolean containsJsr303Annotation;
String typeName;
for (final File f : allJavaSourceInDirectory) {
for (final Class<T> annotationType : annotationTypes) {
typeName = annotationType.getName();
containsJsr303Annotation = FileUtil.isContentInFile(f, typeName);
if (containsJsr303Annotation) {
annotatedSources.add(f);
break; // at least one annotation found, move along
}
}
}
}
// step #4: for each annotated source file parse and rewrite with
// enriched message for each JSR-303 annotation
enrichJavaSourceFilesWithMessageAttributesForConstraintTypeAnnotatedFields(annotatedSources, annotationTypes);
}
// note: probably could have implemented an ASTVisitor, but...
protected void enrichJavaSourceFilesWithMessageAttributesForConstraintTypeAnnotatedFields(
List<File> annotatedSources, Set<Class<T>> constraintTypes) throws IOException, MalformedTreeException,
BadLocationException {
if (!CollectionUtils.isEmpty(annotatedSources)) {
// reusable local variables... a veritable cornucopia
Set<FieldDeclaration> fieldCandidates;
Document document;
String contents;
String constraintName;
String className;
String fieldName;
StringBuilder sb;
AbstractTypeDeclaration td;
IExtendedModifier[] modifiers;
CompilationUnit unit;
AST ast;
MemberValuePair mvp;
Expression exp;
NormalAnnotation na;
// iterate over all java source containing jsr-303 annotated fields
for (final File source : annotatedSources) {
unit = facade.generateCompilationUnitForFile(source);
ast = unit.getAST();
// get the set of fields which are annotated
fieldCandidates = facade.obtainAnnotatedFieldsFromClassInCompilationUnit(unit, constraintTypes);
log.info(source.getName() + " contains " + fieldCandidates.size()
+ " fields with constraint annotations.");
// iterate over each annotated field
for (final FieldDeclaration fd : fieldCandidates) {
modifiers = (IExtendedModifier[]) fd.modifiers().toArray(
new IExtendedModifier[fd.modifiers().size()]);
int i = 0;
// iterate over modifiers for the field
for (final IExtendedModifier modifier : modifiers) {
// interested in Eclipse JDT's DOM form of Annotation
if (modifier instanceof org.eclipse.jdt.core.dom.Annotation) {
// construct the key-value pair
sb = new StringBuilder();
constraintName = ((org.eclipse.jdt.core.dom.Annotation) modifier).getTypeName().toString();
// Ignore #Valid annotations
if (!constraintName.equals(Valid.class.getSimpleName())) {
td = (AbstractTypeDeclaration) fd.getParent();
className = td.getName().toString();
fieldName = fd.fragments().get(0).toString();
// field may have an assignment, so strip it
if (fieldName.contains("=")) {
final int end = fieldName.indexOf("=");
fieldName = fieldName.substring(0, end).trim();
}
sb.append("{");
sb.append(constraintName);
sb.append(".");
sb.append(className);
sb.append(".");
sb.append(fieldName);
sb.append("}");
// construct new properties, and instead of
// updating
// the existing annotation, replace it
mvp = ast.newMemberValuePair();
mvp.setName(ast.newSimpleName("message"));
exp = ast.newStringLiteral();
((StringLiteral) exp).setLiteralValue(sb.toString());
mvp.setValue(exp);
na = ast.newNormalAnnotation();
na.setTypeName(ast.newSimpleName(constraintName));
na.values().add(mvp);
// don't forget to add the original annotation's
// member-value pairs to the new annotation
if (modifier instanceof NormalAnnotation) {
final NormalAnnotation ona = (NormalAnnotation) modifier;
final List<?> values = ona.values();
for (int j = 0; j < values.size(); j++) {
final MemberValuePair omvp = (MemberValuePair) values.get(j);
mvp = ast.newMemberValuePair();
mvp.setName(ast.newSimpleName(omvp.getName().toString()));
// a value can be a String, Number or
// reference to a constant
switch (omvp.getValue().getNodeType()) {
case ASTNode.NUMBER_LITERAL:
mvp.setValue(ast.newNumberLiteral(omvp.getValue().toString()));
break;
case ASTNode.STRING_LITERAL:
exp = ast.newStringLiteral();
((StringLiteral) exp).setLiteralValue(omvp.getValue().toString());
mvp.setValue(exp);
break;
case ASTNode.QUALIFIED_NAME:
final QualifiedName oqn = (QualifiedName) omvp.getValue();
exp = ast.newQualifiedName(ast.newName(oqn.getQualifier().toString()),
ast.newSimpleName(oqn.getName().toString()));
mvp.setValue(exp);
break;
}
na.values().add(mvp);
}
}
fd.modifiers().remove(i);
fd.modifiers().add(i, na);
log.info("#" + constraintName + " on " + fieldName + " in " + className
+ " has been enriched with a 'message' attribute whose value is now '"
+ sb.toString() + "'.");
}
i++;
}
}
}
contents = FileUtil.toString(source);
document = new Document(contents);
facade.saveUpdatesToFile(unit, document, source);
}
}
}
public static void main(String args[]) {
final ConstraintMessageUtil util = new ConstraintMessageUtil();
try {
// e.g., on Windows,
// "D:\\workspaces\\alstom-grid\\SPP-MUI\\spp-im-mui-dto\\src\\main\\java\\org\\spp\\im\\mui\\dto"
util.process(args[0]);
} catch (final Exception e) {
e.printStackTrace();
}
}
}
The utils:
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.AntPathMatcher;
/**
* Package utility. Provides handy methods for finding classes (of a particular
* type) within a package on the classpath.
*
* #author cphillipson
*
* #param <T>
* types of classes to be found in package
*/
class PackageUtil<T> {
public List<Class<T>> listMatchingClasses(String matchPattern) throws IOException {
final List<Class<T>> classes = new LinkedList<Class<T>>();
final PathMatchingResourcePatternResolver scanner = new PathMatchingResourcePatternResolver();
scanner.setPathMatcher(new AntPathMatcher());
final Resource[] resources = scanner.getResources("classpath:" + matchPattern);
for (final Resource resource : resources) {
final Class<T> clazz = getClassFromResource(resource);
classes.add(clazz);
}
return classes;
}
public Class<T> getClassFromResource(Resource resource) {
Class<T> result = null;
try {
String resourceUri = resource.getURI().toString();
resourceUri = resourceUri.substring(0, resourceUri.indexOf(".class")).replace("/", ".");
if (resourceUri.contains("!")) { // class was found in an archive
resourceUri = resourceUri.substring(resourceUri.indexOf("!") + 2);
}
// try printing the resourceUri before calling forName, to see if it
// is OK.
result = (Class<T>) Class.forName(resourceUri);
} catch (final Exception ex) {
ex.printStackTrace();
}
return result;
}
}
/**
* A collection of special-purposed methods for working with files and
* directories. Wraps Apache Commons I/O.
*
* #author cphillipson
*
*/
public class FileUtil {
public static Collection<File> getAllJavaSourceInDirectory(File directory, boolean recursive) {
// scans directory (and sub-directories if recursive flag is true) for
// .java files, returns a collection of files
return FileUtils.listFiles(directory, new String[] { "java" }, recursive);
}
public static boolean isContentInFile(File file, String fragment) throws IOException {
boolean result = false;
final String contents = toString(file);
if (contents.contains(fragment)) { // does file contain fragment?
result = true;
}
return result;
}
public static String toString(File file) throws IOException {
final String result = FileUtils.readFileToString(file, "utf8");
return result;
}
public static void toFile(File file, String content) throws IOException {
FileUtils.writeStringToFile(file, content, "utf8");
}
}
The facade:
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.IExtendedModifier;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spp.im.mui.commons.util.FileUtil;
/**
* Abstract syntax tree facade. Backed by Eclipse JDT, this facade provides a
* number of conveniences, like the ability to:
* <ul>
* <li>generate an {#link CompilationUnit} from a source {#File}</li>
* <li>save updates in a {#link Document} managed by {#link CompilationUnit} to
* a {#link File}</li>
* </ul>
* and much more. Credit goes to <a href=
* "http://svn.apache.org/repos/asf/openejb/branches/eclipse-plugins-1.0.0.alpha/plugins/org.apache.openejb.devtools.core/src/main/java/org/apache/openejb/devtools/core/JDTFacade.java"
* >Apache OpenEJB DevTools JDTFacade source</a> for providing much of the
* inspiration for this implementation.
*
* #author cphillipson
* #param <T>
* any annotation type
*
*/
public class JDTFacade<T extends java.lang.annotation.Annotation> {
private static Logger log = LoggerFactory.getLogger(JDTFacade.class);
public CompilationUnit generateCompilationUnitForFile(File file) throws IOException {
final String source = FileUtil.toString(file);
final Document document = new Document(source);
final ASTParser parser = ASTParser.newParser(AST.JLS4);
parser.setSource(document.get().toCharArray());
final CompilationUnit unit = (CompilationUnit) parser.createAST(null /* no ProgressMonitor */);
unit.recordModifications();
return unit;
}
public void saveUpdatesToFile(CompilationUnit unit, Document document, File file) throws MalformedTreeException,
IOException, BadLocationException {
final TextEdit edits = unit.rewrite(document, null /* no options */);
edits.apply(document);
boolean writeable = true; // should always be able to write to file...
if (!file.canWrite()) { // .. but just in case we cannot...
writeable = file.setWritable(true);
}
if (writeable) {
FileUtil.toFile(file, document.get());
log.info("Successfully wrote updates to " + file.getName());
} else {
log.warn("Unable to write to " + file.getName());
}
}
public Set<FieldDeclaration> obtainAnnotatedFieldsFromClassInCompilationUnit(CompilationUnit unit,
Set<Class<T>> annotationTypes) {
final Set<FieldDeclaration> fields = new HashSet<FieldDeclaration>();
final List<AbstractTypeDeclaration> types = unit.types();
IExtendedModifier[] modifiers;
for (final AbstractTypeDeclaration type : types) {
if (type.getNodeType() == ASTNode.TYPE_DECLARATION) {
// Class def found
final List<BodyDeclaration> bodies = type.bodyDeclarations();
for (final BodyDeclaration body : bodies) {
if (body.getNodeType() == ASTNode.FIELD_DECLARATION) {
final FieldDeclaration field = (FieldDeclaration) body;
modifiers = (IExtendedModifier[]) field.modifiers().toArray(new IExtendedModifier[0]);
for (final IExtendedModifier modifier : modifiers) {
if (!(modifier instanceof Annotation)) {
continue;
}
final Annotation annotationModifer = (Annotation) modifier;
for (final Class<T> clazz : annotationTypes) {
if (annotationModifer.getTypeName().toString().equals(clazz.getCanonicalName())
|| annotationModifer.getTypeName().toString().equals(clazz.getSimpleName())) {
fields.add(field);
break;
}
}
}
}
}
}
}
return fields;
}
}
You cannot modify your code using annotation processing. However, you can create new classes, which can subclass the classes you have and they can contain additional annotations.
If you want to modify your code, you need a library that modifies your code either at compile time or at load time (for example as a special class loader).
I don't know what library would be the best for your case, but BCEL seems to be capable of the task.
See also:
asm
cglib
AspectJ
Create and Read J2SE 5.0 Annotations with the ASM Bytecode Toolkit
post-compilation removal of annotations from byte code
How do you use Java 1.6 Annotation Processing to perform compile time weaving?
Turning one annotation into many annotations with AspectJ

Categories

Resources