How to compile and run java source code in memory [duplicate] - java-compiler-api

This question already has answers here:
Compile code fully in memory with javax.tools.JavaCompiler [duplicate]
(7 answers)
Closed 6 years ago.
I want to treat a String as a Java file then compile and run it. In other words, use Java as a script language.
To get better performance, we should avoid writing .class files to disk.

This answer is from one of my blogs, Compile and Run Java Source Code in Memory.
Here are the three source code files.
MemoryJavaCompiler.java
package me.soulmachine.compiler;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.tools.*;
/**
* Simple interface to Java compiler using JSR 199 Compiler API.
*/
public class MemoryJavaCompiler {
private javax.tools.JavaCompiler tool;
private StandardJavaFileManager stdManager;
public MemoryJavaCompiler() {
tool = ToolProvider.getSystemJavaCompiler();
if (tool == null) {
throw new RuntimeException("Could not get Java compiler. Please, ensure that JDK is used instead of JRE.");
}
stdManager = tool.getStandardFileManager(null, null, null);
}
/**
* Compile a single static method.
*/
public Method compileStaticMethod(final String methodName, final String className,
final String source)
throws ClassNotFoundException {
final Map<String, byte[]> classBytes = compile(className + ".java", source);
final MemoryClassLoader classLoader = new MemoryClassLoader(classBytes);
final Class clazz = classLoader.loadClass(className);
final Method[] methods = clazz.getDeclaredMethods();
for (final Method method : methods) {
if (method.getName().equals(methodName)) {
if (!method.isAccessible()) method.setAccessible(true);
return method;
}
}
throw new NoSuchMethodError(methodName);
}
public Map<String, byte[]> compile(String fileName, String source) {
return compile(fileName, source, new PrintWriter(System.err), null, null);
}
/**
* compile given String source and return bytecodes as a Map.
*
* #param fileName source fileName to be used for error messages etc.
* #param source Java source as String
* #param err error writer where diagnostic messages are written
* #param sourcePath location of additional .java source files
* #param classPath location of additional .class files
*/
private Map<String, byte[]> compile(String fileName, String source,
Writer err, String sourcePath, String classPath) {
// to collect errors, warnings etc.
DiagnosticCollector<JavaFileObject> diagnostics =
new DiagnosticCollector<JavaFileObject>();
// create a new memory JavaFileManager
MemoryJavaFileManager fileManager = new MemoryJavaFileManager(stdManager);
// prepare the compilation unit
List<JavaFileObject> compUnits = new ArrayList<JavaFileObject>(1);
compUnits.add(fileManager.makeStringSource(fileName, source));
return compile(compUnits, fileManager, err, sourcePath, classPath);
}
private Map<String, byte[]> compile(final List<JavaFileObject> compUnits,
final MemoryJavaFileManager fileManager,
Writer err, String sourcePath, String classPath) {
// to collect errors, warnings etc.
DiagnosticCollector<JavaFileObject> diagnostics =
new DiagnosticCollector<JavaFileObject>();
// javac options
List<String> options = new ArrayList<String>();
options.add("-Xlint:all");
// options.add("-g:none");
options.add("-deprecation");
if (sourcePath != null) {
options.add("-sourcepath");
options.add(sourcePath);
}
if (classPath != null) {
options.add("-classpath");
options.add(classPath);
}
// create a compilation task
javax.tools.JavaCompiler.CompilationTask task =
tool.getTask(err, fileManager, diagnostics,
options, null, compUnits);
if (task.call() == false) {
PrintWriter perr = new PrintWriter(err);
for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
perr.println(diagnostic);
}
perr.flush();
return null;
}
Map<String, byte[]> classBytes = fileManager.getClassBytes();
try {
fileManager.close();
} catch (IOException exp) {
}
return classBytes;
}
}
MemoryJavaFileManager.java
package me.soulmachine.compiler;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URI;
import java.nio.CharBuffer;
import java.util.HashMap;
import java.util.Map;
import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.SimpleJavaFileObject;
/**
* JavaFileManager that keeps compiled .class bytes in memory.
*/
#SuppressWarnings("unchecked")
final class MemoryJavaFileManager extends ForwardingJavaFileManager {
/** Java source file extension. */
private final static String EXT = ".java";
private Map<String, byte[]> classBytes;
public MemoryJavaFileManager(JavaFileManager fileManager) {
super(fileManager);
classBytes = new HashMap<>();
}
public Map<String, byte[]> getClassBytes() {
return classBytes;
}
public void close() throws IOException {
classBytes = null;
}
public void flush() throws IOException {
}
/**
* A file object used to represent Java source coming from a string.
*/
private static class StringInputBuffer extends SimpleJavaFileObject {
final String code;
StringInputBuffer(String fileName, String code) {
super(toURI(fileName), Kind.SOURCE);
this.code = code;
}
public CharBuffer getCharContent(boolean ignoreEncodingErrors) {
return CharBuffer.wrap(code);
}
}
/**
* A file object that stores Java bytecode into the classBytes map.
*/
private class ClassOutputBuffer extends SimpleJavaFileObject {
private String name;
ClassOutputBuffer(String name) {
super(toURI(name), Kind.CLASS);
this.name = name;
}
public OutputStream openOutputStream() {
return new FilterOutputStream(new ByteArrayOutputStream()) {
public void close() throws IOException {
out.close();
ByteArrayOutputStream bos = (ByteArrayOutputStream)out;
classBytes.put(name, bos.toByteArray());
}
};
}
}
public JavaFileObject getJavaFileForOutput(JavaFileManager.Location location,
String className,
Kind kind,
FileObject sibling) throws IOException {
if (kind == Kind.CLASS) {
return new ClassOutputBuffer(className);
} else {
return super.getJavaFileForOutput(location, className, kind, sibling);
}
}
static JavaFileObject makeStringSource(String fileName, String code) {
return new StringInputBuffer(fileName, code);
}
static URI toURI(String name) {
File file = new File(name);
if (file.exists()) {
return file.toURI();
} else {
try {
final StringBuilder newUri = new StringBuilder();
newUri.append("mfm:///");
newUri.append(name.replace('.', '/'));
if(name.endsWith(EXT)) newUri.replace(newUri.length() - EXT.length(), newUri.length(), EXT);
return URI.create(newUri.toString());
} catch (Exception exp) {
return URI.create("mfm:///com/sun/script/java/java_source");
}
}
}
}
MemoryClassLoader.java
package me.soulmachine.compiler;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
/**
* ClassLoader that loads .class bytes from memory.
*/
final class MemoryClassLoader extends URLClassLoader {
private Map<String, byte[]> classBytes;
public MemoryClassLoader(Map<String, byte[]> classBytes,
String classPath, ClassLoader parent) {
super(toURLs(classPath), parent);
this.classBytes = classBytes;
}
public MemoryClassLoader(Map<String, byte[]> classBytes, String classPath) {
this(classBytes, classPath, ClassLoader.getSystemClassLoader());
}
public MemoryClassLoader(Map<String, byte[]> classBytes) {
this(classBytes, null, ClassLoader.getSystemClassLoader());
}
public Class load(String className) throws ClassNotFoundException {
return loadClass(className);
}
public Iterable<Class> loadAll() throws ClassNotFoundException {
List<Class> classes = new ArrayList<Class>(classBytes.size());
for (String name : classBytes.keySet()) {
classes.add(loadClass(name));
}
return classes;
}
protected Class findClass(String className) throws ClassNotFoundException {
byte[] buf = classBytes.get(className);
if (buf != null) {
// clear the bytes in map -- we don't need it anymore
classBytes.put(className, null);
return defineClass(className, buf, 0, buf.length);
} else {
return super.findClass(className);
}
}
private static URL[] toURLs(String classPath) {
if (classPath == null) {
return new URL[0];
}
List<URL> list = new ArrayList<URL>();
StringTokenizer st = new StringTokenizer(classPath, File.pathSeparator);
while (st.hasMoreTokens()) {
String token = st.nextToken();
File file = new File(token);
if (file.exists()) {
try {
list.add(file.toURI().toURL());
} catch (MalformedURLException mue) {}
} else {
try {
list.add(new URL(token));
} catch (MalformedURLException mue) {}
}
}
URL[] res = new URL[list.size()];
list.toArray(res);
return res;
}
}
Explanations:
In order to represent a Java source file in memory instead of disk, I defined a StringInputBuffer class in the MemoryJavaFileManager.java.
To save the compiled .class files in memory, I implemented a class MemoryJavaFileManager. The main idea is to override the function getJavaFileForOutput() to store bytecodes into a map.
To load the bytecodes in memory, I have to implement a customized classloader MemoryClassLoader, which reads bytecodes in the map and turn them into classes.
Here is a unite test.
package me.soulmachine.compiler;
import org.junit.Test;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import static org.junit.Assert.assertEquals;
public class MemoryJavaCompilerTest {
private final static MemoryJavaCompiler compiler = new MemoryJavaCompiler();
#Test public void compileStaticMethodTest()
throws ClassNotFoundException, InvocationTargetException, IllegalAccessException {
final String source = "public final class Solution {\n"
+ "public static String greeting(String name) {\n"
+ "\treturn \"Hello \" + name;\n" + "}\n}\n";
final Method greeting = compiler.compileStaticMethod("greeting", "Solution", source);
final Object result = greeting.invoke(null, "soulmachine");
assertEquals("Hello soulmachine", result.toString());
}
}
Reference
JavaCompiler.java from Cloudera Morphlines
How to create an object from a string in Java (how to eval a string)?
InMemoryJavaCompiler
Java-Runtime-Compiler
动态的Java - 无废话JavaCompilerAPI中文指南

Related

RedissonClient is throwing StringIndexOutOfBoundsException: begin 8, end 5, length 22

I have below code for Redis Configuration, i need to use RedissonClient to flush cache after regular intervals.Using timerTask to run flush code. CacheManager and Proxy Manager is used because it is connected to bucket4j Ratelimiting code.
Connection to Docker Redis Image is successful as well. Using redisson version 3.12.5.
Following this doc: https://www.freecodecamp.org/news/rate-limiting-with-bucket4j-and-redis/
import io.github.bucket4j.distributed.proxy.ProxyManager;
import io.github.bucket4j.grid.jcache.JCacheProxyManager;
import java.util.Iterator;
import java.util.Timer;
import java.util.TimerTask;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.spi.CachingProvider;
import lombok.extern.log4j.Log4j2;
import org.ehcache.jsr107.EhcacheCachingProvider;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.jcache.configuration.RedissonConfiguration;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.utility.DockerImageName;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
#Log4j2
#Configuration
public class RedisConfig {
private static GenericContainer redis = null;
private RedissonClient redisson;
private final Timer timer = new Timer("RedisConfig", true);
private final CleanupRedis clean = new CleanupRedis(this);
public RedisConfig(){
timer.scheduleAtFixedRate(clean, SECONDS.toMillis(2), MINUTES.toMillis(2));
}
#Bean(name = "client")
public RedissonClient client() {
Config config = new Config();
if (redis == null) {
redis = new GenericContainer<>(redisImageName()).withExposedPorts(6379);
redis.start();
}
System.setProperty("spring.redis.host", redis.getHost());
System.setProperty("spring.redis.port", redis.getMappedPort(6379).toString());
config
.useSingleServer()
.setAddress("redis://" + redis.getHost() + redis.getMappedPort(6379));
RedissonClient rdson = Redisson.create(config);
return rdson;
}
#Bean
public CacheManager cacheManager(#Qualifier("client") RedissonClient redissonClient) {
Iterator<CachingProvider> iterator =
Caching.getCachingProviders(Caching.getDefaultClassLoader()).iterator();
while (iterator.hasNext()) {
CachingProvider provider = iterator.next();
if (!(provider instanceof EhcacheCachingProvider)) {
iterator.remove();
}
}
CacheManager manager = Caching.getCachingProvider().getCacheManager();
manager.createCache("cache", RedissonConfiguration.fromConfig(redissonClient.getConfig()));
return manager;
}
private static DockerImageName redisImageName() {
return DockerImageName.parse("docker.io/redis:5.0.3-alpine")
.asCompatibleSubstituteFor("redis:5.0.3-alpine");
}
#Bean
ProxyManager<String> proxyManager(CacheManager cacheManager) {
return new JCacheProxyManager<>(cacheManager.getCache("cache"));
}
protected class CleanupRedis extends TimerTask {
private RedisConfig redisConfig;
CleanupRedis(RedisConfig redisConfig) {
this.redisConfig = redisConfig;
}
#Override
public void run() {
try {
System.out.println("Redisson client call is being made");
RedissonClient redisson = Redisson.create(client().getConfig());
System.out.println("Redisson client is not working");
redisson.getKeys().flushdb();
log.debug("Successfully cleared the Redis Cache");
redisson.shutdown();
} catch (Exception e) {
log.debug("caught exception cleanup availability: {}", e.getMessage());
}
}
}
}

Unable to initialize AdaptersAPI Object in MobileFirst V8.0 adapter which is leading to NullPointerException

I am developing the adapter in MFP V8. Below is my code to validate username and password:
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Logger;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import com.ibm.mfp.adapter.api.AdaptersAPI;
import com.ibm.mfp.adapter.api.ConfigurationAPI;
import com.ibm.mfp.security.checks.base.UserAuthenticationSecurityCheck;
import com.ibm.mfp.server.registration.external.model.AuthenticatedUser;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
#Api(value = "Sample Adapter Resource")
#Path("/resource")
public class UserValidationSecurityCheck extends UserAuthenticationSecurityCheck{
private String displayName;
private String errorMsg;
private HashMap<String,Object> adapterReponse = null;
#Context
AdaptersAPI adaptersAPI;
#Override
protected AuthenticatedUser createUser() {
return new AuthenticatedUser(displayName, displayName, this.getName(),adapterReponse);
}
#Override
protected boolean validateCredentials(Map<String, Object> credentials) {
if(credentials!=null && credentials.containsKey("username") && credentials.containsKey("password")){
if (credentials.get("username")!=null && credentials.get("password")!=null) {
String username = credentials.get("username").toString();
String password = credentials.get("password").toString();
if (username.equals(password)) {
JSONObject loginParams = new JSONObject();
loginParams.put("username", username);
loginParams.put("password", password);
HttpUriRequest httpUriRequest = adaptersAPI.createJavascriptAdapterRequest("LoginAndWeeklyCertAdapter1", "login", loginParams);
try {
HttpResponse httpResponse = adaptersAPI.executeAdapterRequest(httpUriRequest);
adapterReponse = adaptersAPI.getResponseAsJSON(httpResponse);
System.out.println(adapterReponse.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true;
} else {
errorMsg = "Wrong Credentials";
}
}
}
else{
errorMsg = "Credentials not set properly";
}
return false;
}
public boolean isLoggedIn(){
return getState().equals(STATE_SUCCESS);
}
public AuthenticatedUser getRegisteredUser() {
return registrationContext.getRegisteredUser();
}
#Override
protected Map<String, Object> createChallenge() {
Map<String, Object> challenge = new HashMap<String, Object>();
challenge.put("errorMsg", errorMsg);
challenge.put("remainingAttempts", getRemainingAttempts());
return challenge;
}
#ApiOperation(value = "Returns 'Hello from resource'", notes = "A basic example of a resource returning a constant string.")
#ApiResponses(value = { #ApiResponse(code = 200, message = "Hello message returned") })
#GET
#Produces(MediaType.TEXT_PLAIN)
public String getResourceData() {
// log message to server log
logger.info("Logging info message...");
return "Hello from resource";
}
}
When I am submitting the challenge answer I am getting NullPointerException in following line:
HttpUriRequest httpUriRequest = adaptersAPI.createJavascriptAdapterRequest("LoginAndWeeklyCertAdapter1", "login");
because adaptersAPI is null. Do I have to do any extra configuration in order to make that work? How can I initialize AdaptersAPI object?
Note: The login method and the security check both are in same adapter.
Update
I investigated more of time into it and updated the code to given above and observed the following:
1. When validateCredentials() is getting called after submitting the challenge response then I am getting null value in AdapterAPI object.
2. Where as, when I am calling the getResourceData() using the mobilefirst swagger tool then I am getting an object of AdapterAPI.
We cannot inject the adapters API into a security check object(by design - not a bug). The only way we can go is to extract the logic from Adapter into a Java code, without using adapters API.

Apache FOP the method newInstance(FopFactoryConfig) in the type FopFactory is not applicable for the arguments ()

I am getting the following error:
Exception in thread "main" java.lang.Error: Unresolved compilation problem: The method newInstance(FopFactoryConfig) in the type FopFactory is not applicable for the arguments ()
at fopdemo.fopvass.PDFHandler.createPDFFile(PDFHandler.java:42)
at fopdemo.fopvass.TestPDF.main(TestPDF.java:40)
This is my code:
package fopdemo.fopvass;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URL;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMResult;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.sax.SAXResult;
import javax.xml.transform.stream.StreamSource;
import org.apache.fop.apps.FOPException;
import org.apache.fop.apps.FOUserAgent;
import org.apache.fop.apps.Fop;
import org.apache.fop.apps.FopFactory;
import org.apache.fop.apps.MimeConstants;
public class PDFHandler {
public static final String EXTENSION = ".pdf";
public String PRESCRIPTION_URL = "template.xsl";
public String createPDFFile(ByteArrayOutputStream xmlSource, String templateFilePath) throws IOException {
File file = File.createTempFile("" + System.currentTimeMillis(), EXTENSION);
URL url = new File(templateFilePath + PRESCRIPTION_URL).toURI().toURL();
// creation of transform source
StreamSource transformSource = new StreamSource(url.openStream());
// create an instance of fop factory
FopFactory fopFactory = FopFactory.newInstance();
// a user agent is needed for transformation
FOUserAgent foUserAgent = fopFactory.newFOUserAgent();
// to store output
ByteArrayOutputStream pdfoutStream = new ByteArrayOutputStream();
StreamSource source = new StreamSource(new ByteArrayInputStream(xmlSource.toByteArray()));
Transformer xslfoTransformer;
try {
TransformerFactory transfact = TransformerFactory.newInstance();
xslfoTransformer = transfact.newTransformer(transformSource);
// Construct fop with desired output format
Fop fop;
try {
fop = fopFactory.newFop(MimeConstants.MIME_PDF, foUserAgent, pdfoutStream);
// Resulting SAX events (the generated FO)
// must be piped through to FOP
Result res = new SAXResult(fop.getDefaultHandler());
// Start XSLT transformation and FOP processing
try {
// everything will happen here..
xslfoTransformer.transform(source, res);
// if you want to save PDF file use the following code
OutputStream out = new java.io.FileOutputStream(file);
out = new java.io.BufferedOutputStream(out);
FileOutputStream str = new FileOutputStream(file);
str.write(pdfoutStream.toByteArray());
str.close();
out.close();
} catch (TransformerException e) {
e.printStackTrace();
}
} catch (FOPException e) {
e.printStackTrace();
}
} catch (TransformerConfigurationException e) {
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
e.printStackTrace();
}
return file.getPath();
}
public ByteArrayOutputStream getXMLSource(EmployeeData data) throws Exception {
JAXBContext context;
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
try {
context = JAXBContext.newInstance(EmployeeData.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(data, System.out);
m.marshal(data, outStream);
} catch (JAXBException e) {
e.printStackTrace();
}
return outStream;
}
}
This is where it is called:
package fopdemo.fopvass;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
/**
* #author Debasmita.Sahoo
*
*/
public class TestPDF {
public static void main(String args[]){
System.out.println("Hi Testing");
ArrayList employeeList = new ArrayList();
String templateFilePath ="C:/Paula/Proyectos/fop/fopvass/resources/";
Employee e1= new Employee();
e1.setName("Debasmita1 Sahoo");
e1.setEmployeeId("10001");
e1.setAddress("Pune");
employeeList.add(e1);
Employee e2= new Employee();
e2.setName("Debasmita2 Sahoo");
e2.setEmployeeId("10002");
e2.setAddress("Test");
employeeList.add(e2);
Employee e3= new Employee();
e3.setName("Debasmita3 Sahoo");
e3.setEmployeeId("10003");
e3.setAddress("Mumbai");
employeeList.add(e3);
EmployeeData data = new EmployeeData();
data.setEemployeeList(employeeList);
PDFHandler handler = new PDFHandler();
try {
ByteArrayOutputStream streamSource = handler.getXMLSource(data);
handler.createPDFFile(streamSource,templateFilePath);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
The following line won't compile:
FopFactory fopFactory = FopFactory.newInstance();
The method newInstance() requires a parameter. From the documentation (provided by Mathias Muller), under 'Basic Usage', that parameter refers to a configuration file:
FopFactory fopFactory = FopFactory.newInstance(
new File( "C:/Temp/fop.xconf" ) );
You need to provide it a File object. Alternatively, it is also possible to create a FopFactory instance by providing a URI to resolve relative URIs in the input file (because SVG files reference other SVG files). As the documentation suggests:
FopFactory fopFactory = FopFactory.newInstance(
new File(".").toURI() );
The user agent is the entity that allows you to interact with a single rendering run, i.e. the processing of a single document. If you wish to customize the user agent's behaviour, the first step is to create your own instance of FOUserAgent using the appropriate factory method on FopFactory and pass that to the factory method that will create a new Fop instance.
FopFactory.newInstance() support
FopFactory.newInstance(File)
FopFactory.newInstance(Uri)
FopFactory.newInstance(Uri, InputStream)
FopFactory.newInstance(FopFactoryConfig)
I successfully implemented on Windows and Mac OS (i.e. a Unix\Linux like NFS) the following code
URI uri = new File(config.getRoot()).toPath().toUri();
FopFactory fopFactory = FopFactory.newInstance(uri);
On the other hand, this does not work (and I don't understand why)
URI uri = new File(config.getRoot()).toUri();

SQL Query to JTable NullPointerException

This runs perfectly:
package sledmonitor;
import java.io.File;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
public class GetList3 {
private Connection conn;
private String ConnectURL = "jdbc:odbc:Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=." + File.separator + "db" + File.separator + "sledprod.mdb";
private String user = "";
private String pw = "";
String offer;
GetList3(String sql){
try{
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
conn = DriverManager.getConnection(ConnectURL, user, pw);
Statement stmt = conn.createStatement();
System.out.println(sql);
ResultSet rs = stmt.executeQuery(sql);
while(rs.next()){
offer = rs.getString("offernumber");
System.out.println(offer);
}
rs.close();
stmt.close();
}
catch(Exception e){
e.printStackTrace();
}
finally{
if(conn!=null){
try{
conn.close();
}
catch(Exception e){
e.printStackTrace();
}
}
}
}
}
Now I would like to show the Results in a JTable. So I make this, what normaly should work:
while(rs.next()){
offer = rs.getString("offernumber");
List.tablemodel.addRow(new String[]{offer});
}
But this somehow throws following NullPointerException:
SELECT o.offernumber, o.TotalMPL
FROM sled_offers o left join sled_changes c on o.offerguid = c.objectid
WHERE (c.nextsequencenr is null or c.nextsequencenr=99999) AND TotalMPL='0'
AND (o.offerstate=2 or o.offerstate=4 or o.offerstate=5)
java.lang.NullPointerException
at sledmonitor.GetList3.<init>(GetList3.java:28)
at sledmonitor.GetList.<init>(GetList.java:45)
at sledmonitor.Monitor$4.mouseClicked(Monitor.java:99)
at java.awt.AWTEventMulticaster.mouseClicked(AWTEventMulticaster.java:270)
at java.awt.Component.processMouseEvent(Component.java:6508)
at javax.swing.JComponent.processMouseEvent(JComponent.java:3321)
at java.awt.Component.processEvent(Component.java:6270)
at java.awt.Container.processEvent(Container.java:2229)
at java.awt.Component.dispatchEventImpl(Component.java:4861)
at java.awt.Container.dispatchEventImpl(Container.java:2287)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4832)
at java.awt.LightweightDispatcher.processMouseEvent(Container.java:4501)
at java.awt.LightweightDispatcher.dispatchEvent(Container.java:4422)
at java.awt.Container.dispatchEventImpl(Container.java:2273)
at java.awt.Window.dispatchEventImpl(Window.java:2719)
at java.awt.Component.dispatchEvent(Component.java:4687)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:703)
at java.awt.EventQueue.access$000(EventQueue.java:102)
at java.awt.EventQueue$3.run(EventQueue.java:662)
at java.awt.EventQueue$3.run(EventQueue.java:660)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:87)
at java.awt.EventQueue$4.run(EventQueue.java:676)
at java.awt.EventQueue$4.run(EventQueue.java:674)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(ProtectionDomain.java:76)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:673)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:244)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:163)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:151)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:147)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:139)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:97)
The class List looks like this:
package sledmonitor;
import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.table.DefaultTableModel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
public class List extends JFrame {
private JPanel contentPane;
private JTable table;
static DefaultTableModel tablemodel;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
List frame = new List();
frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the frame.
*/
public List() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setBounds(100, 100, 450, 300);
contentPane = new JPanel();
contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
contentPane.setLayout(new BorderLayout(0, 0));
setContentPane(contentPane);
JScrollPane scrollPane = new JScrollPane();
contentPane.add(scrollPane, BorderLayout.CENTER);
tablemodel = new DefaultTableModel();
tablemodel.addColumn("OfferNumber");
table = new JTable(tablemodel);
scrollPane.setViewportView(table);
}
}
Any idea?
You seem to be accessing the static field List.tablemodel without instanciating first the List object, so you aren't calling List() which doesn't instanciate your tablemodel object.
You should then use a static constructor:
static {
tablemodel = new DefaultTableModel();
tablemodel.addColumn("OfferNumber");
}
And remove those 2 lines of code from the List() constructor.
use this
DefaultTableModel myData = new DefaultTableModel();
JTable table = new JTable(myData);
// initialize the table with model type constructor
while(rs.next()){
String offer = rs.getString("offernumber");
Object [] rowData=new Object[]{offer,null};
myData.addRow(rowData);
}
//use addRow(Object[] rowData) method of defaulttablemodel class

custom schema to XMP metadata

I want to write custom metadata to a pdf file which are not supported by XMP standard schemas hence I wrote my own schema containing my own properties. I can successfully write these additional custom metadata to my PDF file using either PDFBox or iTextPDF library. I am however unable to read the custom metadata at client side without parsing the XMP xml.
I guess there should be some API that I am not aware of for getting your custom schema back to your java class.
Please help me if I am thinking in right direction or do I actually need to parse the xml for getting my custom data back at client side?
Here is the code I wrote using PDFBox library
Custom Metadata File.
package com.ecomail.emx.core.xmp;
import java.io.IOException;
import org.apache.jempbox.xmp.XMPMetadata;
public class EMXMetadata extends XMPMetadata {
public EMXMetadata() throws IOException {
super();
}
public EMXSchema addEMXSchema() {
EMXSchema schema = new EMXSchema(this);
return (EMXSchema) basicAddSchema(schema);
}
public EMXSchema getEMXSchema() throws IOException {
return (EMXSchema) getSchemaByClass(EMXSchema.class);
}
}
Custom Schema File.
package com.ecomail.emx.core.xmp;
import java.util.List;
import org.apache.jempbox.xmp.XMPMetadata;
import org.apache.jempbox.xmp.XMPSchema;
import org.w3c.dom.Element;
public class EMXSchema extends XMPSchema {
public static final String NAMESPACE = "http://www.test.com/emx/elements/1.1/";
public EMXSchema(XMPMetadata parent) {
super(parent, "test", NAMESPACE);
}
public EMXSchema(Element element, String prefix) {
super(element, prefix);
}
public String getMetaDataType() {
return getTextProperty(prefix + ":metaDataType");
}
public void setMetaDataType(String metaDataType) {
setTextProperty(prefix + ":metaDataType", metaDataType);
}
public void removeRecipient(String recipient) {
removeBagValue(prefix + ":recipient", recipient);
}
public void addRecipient(String recipient) {
addBagValue(prefix + ":recipient", recipient);
}
public List<String> getRecipients() {
return getBagList(prefix + ":recipient");
}
}
XML Client File.
package com.ecomail.emx.core.xmp;
import java.util.GregorianCalendar;
import org.apache.jempbox.xmp.XMPMetadata;
import org.apache.jempbox.xmp.XMPSchemaDublinCore;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
public class XMPClient {
private XMPClient() {
}
public static void main(String[] args) throws Exception {
PDDocument document = null;
try {
document = PDDocument.load("/home/silver/SVNRoot/ecomail/trunk/sample.pdf");
PDDocumentCatalog catalog = document.getDocumentCatalog();
PDDocumentInformation info = document.getDocumentInformation();
EMXMetadata metadata = new EMXMetadata();
XMPSchemaDublinCore dcSchema = metadata.addDublinCoreSchema();
dcSchema.setTitle(info.getTitle());
dcSchema.addContributor("Contributor");
dcSchema.setCoverage("coverage");
dcSchema.addCreator("PDFBox");
dcSchema.addDate(new GregorianCalendar());
dcSchema.setDescription("description");
dcSchema.addLanguage("language");
dcSchema.setCoverage("coverage");
dcSchema.setFormat("format");
EMXSchema emxSchema = metadata.addEMXSchema();
emxSchema.addRecipient("Recipient 1");
emxSchema.addRecipient("Recipient 2");
PDMetadata metadataStream = new PDMetadata(document);
metadataStream.importXMPMetadata(metadata);
catalog.setMetadata(metadataStream);
document.save("/home/silver/SVNRoot/ecomail/trunk/sample1.pdf");
document.close();
document = PDDocument.load("/home/silver/SVNRoot/ecomail/trunk/sample1.pdf");
PDDocumentCatalog catalog2 = document.getDocumentCatalog();
PDMetadata metadataStream2 = catalog2.getMetadata();
XMPMetadata metadata2 = metadataStream2.exportXMPMetadata();
EMXSchema emxSchema2 = (EMXSchema) metadata2.getSchemaByClass(EMXSchema.class);
System.out.println("recipients : " + emxSchema2.getRecipients());
} finally {
if (document != null) {
document.close();
}
}
}
}
In the XMPClient file I am expecting that I will get EMXSchema object back from the resulatant meta data by querying it from its class name.
XMPMetadata metadata2 = metadataStream2.exportXMPMetadata();
EMXSchema emxSchema2 = (EMXSchema) metadata2.getSchemaByClass(EMXSchema.class);
System.out.println("recipients : " + emxSchema2.getRecipients());
But I am getting Null Pointer Exception indicating this was not found.
Can anybody please help me if I am doing it right way or do I need to parse the XMP to get my recipients values.
Thanks
Finally I got it working myself.
The solution is to use the another constructor of the XMPMetadata class that accepts a predefined document class.
document = PDDocument.load("/home/silver/SVNRoot/ecomail/trunk/sample1.pdf");
PDDocumentCatalog catalog2 = document.getDocumentCatalog();
PDMetadata metadataStream2 = catalog2.getMetadata();
System.out.println(metadataStream2.getInputStreamAsString());
InputStream xmpIn = metadataStream2.createInputStream();
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setExpandEntityReferences(true);
f.setIgnoringComments(true);
f.setIgnoringElementContentWhitespace(true);
f.setValidating(false);
f.setCoalescing(true);
f.setNamespaceAware(true);
DocumentBuilder builder = f.newDocumentBuilder();
Document xmpDoc = builder.parse(xmpIn);
EMXMetadata emxMetadata = new EMXMetadata(xmpDoc);
EMXSchema emxSchema2 = emxMetadata.getEMXSchema();
System.out.println("recipients : " + emxSchema2.getRecipients());
Now my custom emxMetadata contains non null emxSchema2 object and I can get back my recipient objects from it. However to make it work I had to modify EMXMetadata to support XMLNamespaceMapping for your schema class
public class EMXMetadata extends XMPMetadata {
public EMXMetadata() throws IOException {
super();
addXMLNSMapping(EMXSchema.NAMESPACE, EMXSchema.class);
}
public EMXMetadata(Document xmpDoc) {
super(xmpDoc);
addXMLNSMapping(EMXSchema.NAMESPACE, EMXSchema.class);
}
public EMXSchema addEMXSchema() {
EMXSchema schema = new EMXSchema(this);
return (EMXSchema) basicAddSchema(schema);
}
public EMXSchema getEMXSchema() throws IOException {
return (EMXSchema) getSchemaByClass(EMXSchema.class);
}
}