7

I'm using MATLAB R2007b, Java 1.6 SE, Eclipse Helios, and MySql 5 on Windows XP Pro SP3.

I'm trying to create a class library that uses JPA annotations to access a MySql 5 database. The idea is that the MATLAB script instantiates these Java objects, which provide an API for accessing the DB.

I can create my annotated classes, which work within Eclipse (i.e. JUnit test). I can export the code to a jar, which I can run from a command prompt.

I update the MATLAB Java classpath using javaaddpath(). I can instantiate my class within MATLAB. But when I call my init(), which calls javax.persistence.Persistence.createEntityManagerFactory(), I get the dreaded

"No Persistence provider for EntityManager"

This error usually means that the persistence.xml file isn't in the right place. But it must be because my jar works from the command line. Adding the META-INF folder to the MATLAB java classpath doesn't help. Nor does extracting the jar and adding the extracted folder structure to the classpath, whether or not META-INF is added.

Does anyone have any ideas, nutty or not? Has anyone ever done this in any version of MATLAB.

Thanks.

-reilly.

Jim Tough
  • 14,843
  • 23
  • 75
  • 96
Reilly
  • 826
  • 9
  • 18

5 Answers5

8

Well, I found "an answer." Somewhere before I saw a post about the difference in MATLAB's "dynamic" and "static" cp's. The "static" cp is a text file that is loaded at startup. The "dynamic" cp is loaded at runtime and you typically manipulate it with m-script calls. That's what I was trying to do.

So I added my jars to the dynamic path and it didn't work.

I added them to the end of the static path and got DIFFERENT errors, which seemed to pertain to the XML parsing. Progress!

Then I added my jars to the BEGINNING of the static path and it works.

To quote Bart Simpson: Craptackular.

Thanks for all your ideas. Ask me a C# question so I can reciprocate...

-reilly.

Reilly
  • 826
  • 9
  • 18
  • 3
    Makes sense - the static classpath corresponds to the system classloader; the dynamic classpath is done with a custom Matlab URLClassLoader. APIs like JAX-WS that need to vivify classes can run in to problems because the API classes on the static classpath can't "see" class definitions loaded in to the dynamic classpath; JPA probably had the same problem. If you're modifying the static classpath, you can use a custom classpath.txt in the directory you're starting Matlab in instead of editing classpath.txt in the Matlab installation itself; easier maintenance. – Andrew Janke Dec 07 '10 at 18:58
  • 1
    Thanks, Andrew. I didn't know about my own classpath.txt. That takes care of my main complaint with this issue. – Reilly Dec 07 '10 at 20:35
  • For the record and cross-reference, here's the post Reilly was talking about, on CSSM: http://www.mathworks.com/matlabcentral/newsreader/view_thread/298304#802849 – Yair Altman Dec 09 '10 at 00:58
8

While working with Java in MATLAB, I often encountered issues with the dynamic classpath. As a workaround, using classpath.txt has solved any issue so far.

Dealing with different environments, for example testing and production, results in multiple classpath.txt files in your MATLAB start directory. Using different MATLAB releases adds another multiplier to the number of classpath.txt files around.

ClassPathHacker.java is an option to add dynamically classes and jar files to your static classpath. Using this approach there is no need to touch classpath.txt anymore. Your Java classpath configuration can stay in the intended place startup.m.

Community
  • 1
  • 1
zellus
  • 9,617
  • 5
  • 39
  • 56
  • +1 This looks very useful! My Matlab app actually does have those nenvironments x nmatlabversions different startup dirs with these custom files; this could really simplify things. – Andrew Janke Dec 07 '10 at 19:14
3

This is just a followup to your answer about static vs dynamic classpaths. Here's a function which will let you diagnose where a Java class is being loaded from within Matlab, and if there's any masking of the class definitions, which could be why it was sensitive to ordering for you. You might see other collisions; at least dom4j.jar and commons-collections.jar are shipped with Matlab, but I don't know what versions.

function whereisjavaclassloadingfrom(ClassName)
%WHEREISJAVACLASSLOADINGFROM  Show where a Java class is loaded from
%
% whereisjavaclassloadingfrom(ClassName)
%
% Shows where a Java class is loaded from in this Matlab session's JVM.
% This is for diagnosing Java class load problems, such as classpath
% ordering issues, seeing if a class of a given name is included in an
% unexpected JAR file, etc.
%
% Displays output to console.
%
% Examples:
%
% whereisjavaclassloadingfrom('java.util.HashMap')
% whereisjavaclassloadingfrom('com.ldhenergy.etools.MxUtil')
% whereisjavaclassloadingfrom('com.google.common.collect.Maps')
% whereisjavaclassloadingfrom('org.apache.commons.math.complex.Complex')

% Use javaArray to get Class object without having to instantiate. This
% lets it work with objects that have private or non-zero-arg constructors,
% and avoids side effects of object construction.
% (Would use java.lang.Class.forName(), because that's a more direct way of
% doing this, but it doesn't work for stuff on the dynamic classpath.)
ja = javaArray(ClassName,1);
klass = ja.getClass().getComponentType();

klassLoader = klass.getClassLoader();
if isempty(klassLoader)
    % JVM used null to represent the "bootstrap" class loader
    % I think that's the same as the "system" class loader
    klassLoader = java.lang.ClassLoader.getSystemClassLoader();
end
klassLoaderStr = char(klassLoader.toString());

klassFilePath = [strrep(ClassName, '.', '/') '.class'];
try
    % This logic assumes that the classes exist as files in the class
    % loader. It's a valid assumption for mainstream class loaders,
    % including the one's I've seen with Matlab.
    klassUrl = klassLoader.getResource(klassFilePath);
    if isempty(klassUrl)
        klassUrlStr = '';
    else
        klassUrlStr = char(klassUrl.toString());
    end
catch err
    klassUrlStr = sprintf('ERROR: %s', err.message);
end

% Get all locations, to reveal masked definitions
urls = enumeration2array(klassLoader.getResources(klassFilePath));

disp(sprintf('Version: %s\nClass:       %s\nClassLoader: %s\nURL:         %s', version,...
    char(klass.getName()), klassLoaderStr, klassUrlStr));
if numel(urls) > 1
    disp('Class is masked:');
    for i = 1:numel(urls)
        disp(sprintf('URL %d:       %s', i, char(urls(i))));
    end
end

%%
function out = enumeration2array(jenum)
tmp = {};
while jenum.hasMoreElements()
    tmp{end+1} = jenum.nextElement();
end
out = [tmp{:}];
Andrew Janke
  • 23,508
  • 5
  • 56
  • 85
2

Ensure that you have a JPA provider jar (such as eclipselink.jar) on your classpath.

James
  • 17,965
  • 11
  • 91
  • 146
  • +1 This is a good candidate. Matlab manages its own Java class path, so it won't necessarily be the same as what the command line "java" command sees. As of R2010b, Matlab does not ship with javax.persistence, so you'll need to supply a JAR for it as well as the JAR with your own classes. – Andrew Janke Dec 07 '10 at 15:01
  • Yep. Here's what I have on my MATLAB classpath: – Reilly Dec 07 '10 at 18:12
  • antlr-2.7.6.jar com.barronassociates.auspex.rotorcraft.jar commons-collections-3.1.jar dom4j.jar ejb3-persistence.jar hibernate3.jar hibernate-annotations.jar hibernate-commons-annotations.jar hibernate-core.jar hibernate-entitymanager.jar javassist.jar jta.jar mysql-connector-java-5.1.7-bin.jar slf4j-api-1.5.6.jar slf4j-simple-1.5.6.jar – Reilly Dec 07 '10 at 18:13
0

Are you absolutely certain that you have spelled the name of the persistence unit correctly in the call to:

javax.persistence.Persistence.createEntityManagerFactory(String puName)

That would also give you the same error. The name is case-sensitive.

Jim Tough
  • 14,843
  • 23
  • 75
  • 96
  • Yes. The persistence unit name is hard-coded in my Java class, so the same value gets passed whether I run from MATLAB or from java in the command line. – Reilly Dec 07 '10 at 13:13