Due to project requirement we need to import the project mappings & other objects from a different server. But we found that all the mapping context becomes undefined.
I am trying to write a groovy program to set the context at a bulk. I have written the below code but somehow the interfaceList is empty and thus unable to perform odiInterface.setOptimizationContext(context);.
Below is my code. For brevity I haven't mentioned the packages stmt.
def all the variables like url,driver,schema etc
def all variables like MasterInfo, auth, transaction, etc
def OdiContext context = ((IOdiContextFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiContext.class)).findByCode("CTX_ANN1_S4")
for (p in odiProjectList) {
if (p.getName() == "PrjDemo_TA") {
def OdiFolderList = p.getFolders()
for (f in OdiFolderList) {
if (f.getName() == "TrgDemoMod_Comn_TA_S4") {
// def OdiInterfaceList2 = f.getInterfaces()
// def OdiMappingList = odiInstance.getTransactionalEntityManager().findAll( Mapping.class)
def OdiInterfaceList = ((IOdiInterfaceFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiInterface.class)).findByProject(projectCode, folderName)
for (m in OdiInterfaceList2) {
println(m.getName() + "|" + m.getClass()) //+ "|" + m.getParent() + "|" + m.getFolder() )
m.setOptimizationContext(context)
}
tm.commit(txnStatus)
}
}
}
}
The line which initializes OdiInterfaceList is not throwing any error nor populating desired interface lists of all the interfaces within a folder.
So m.setOptimizationContext(context) is not executed.
If i substitute that line with:
def OdiMappingList = odiInstance.getTransactionalEntityManager().findAll( Mapping.class)
within a for ... loop i can able to access the mappings but I don't know how to set its context OdiMappingList as setOptimizationContext is an interface's method.
I'm unable to reproduce your case as I don't have the environment to test it, but I still think I can help.
First, I refactored your code so its more groovy:
def OdiContext context = ((IOdiContextFinder) odiInstance.getTransactionalEntityManager().getFinder(OdiContext.class)).findByCode("CTX_ANN1_S4")
// Looking for the project
def prjDemo = odiProjectList.find { it.name == "PrjDemo_TA" }
assert prjDemo : "Unable to find ODI project"
//Getting the Mappings
def mappingList = odiInstance.getTransactionalEntityManager().findAll( Mapping.class)
assert ! mappingList.toList().empty : "Mappings not found"
// Printing interfaces
mappingList.each {
it.setDefaultContext(context as IContext)
}
With those asserts, you may be able to know more in detail where your code may be really failing.
I noticed that IOdiInterfaceFinder is marked as deprecated, so it might not play well with Oracle 12c. Check your versions.
Probably it would be better if you try to replace that deprecated code with a more updated version. I found some similar code to yours in this page, so it might be useful.
UPDATE:
Updated the code to use Mapping class. As it has setDefaultContext(IContext ctx) method and OdiContext implements IContext, maybe it might work.
Related
I'm new to Scala, and I can't figure out how to solve a compiling error for method withTransaction :
Cannot resolve overloaded method 'withTransaction'
object Global {
def goBootstrap(app: Application) {
Logger.info(" **** start *****")
onGet();
}
def onGet() {
import play.db.jpa.JPA
Logger.info("Cnnection start");
JPA.withTransaction(JPA.em =>
{
val resultsList = JPA.em.createNamedQuery("findCity").setParameter("name", "Boston").getResultList
}
);
}
}
This code snippet is located in a Global.scala file in Play project (version 2.3.X). JPA came from import play.db.jpa.JPA
How can I solve this compiling error?
The error is telling you that there is no method on JPA whose signature matches the parameters you're passing. You are calling JPA.withTransaction( () => Unit).
Looking at the source there are three methods withTransaction with Unit return types:
void withTransaction(Consumer<EntityManager> block);
void withTransaction(String name, Consumer<EntityManager> block);
void withTransaction(String name, boolean readOnly, Consumer<EntityManager> block);
I'm going to assume that you're trying to use the first of those methods. Looking at the docs for Consumer it requires a single argument.
In short, you need to provide an input to your block, something like:
JPA.withTransaction(JPA.em => {
val resultsList = JPA.em.createNamedQuery("findCity").setParameter("name", name).getResultList
});
The problem is that you can't directly instantiate a JPA connection through scala. Also because the play 2.3 framework does not support this feature: https://www.playframework.com/documentation/2.3.x/ScalaHome
Is there a command line tool that can automatically fix non formatting but still seemingly simple CheckStyle issues in Java source code like:
Avoid inline conditionals
Make "xxx" a static method
I know there are various tools to fix formatting and some IDEs have fairly advanced quick fixers but so far I could not find anything that can recursively run on a source code folder or be integrated in a commit hook.
Sounds like a nice challenge, but I was also unable to find an automatic tool that can do this. As you already described, there are plenty of options to change code formatting. For other small issues, you could perhaps run Checkstyle from the command-line and filter out fixable warnings. A library for parsing and changing Java source code could help to actually make the changes, like for example JavaParser. Perhaps you could write a custom tool in a relatively small amount of time using a Java source code manipulation tool like JavaParser.
(There are other tools like ANTLR that could be used; see for more ideas this question on Stack Overflow: Java: parse java source code, extract methods. Some libraries like Roaster and JavaPoet do not parse the body of methods, which makes them less suitable in this situation.)
As a very simple example, assume we have a small Java class for which Checkstyle generates two messages (with a minimalistic checkstyle-checks.xml Checkstyle configuration file that only checks FinalParameters and FinalLocalVariable):
// Example.java:
package q45326752;
public class Example {
public static void main(String[] arguments) {
System.out.println("Hello Checkstyle...");
int perfectNumber = 1 + 2 + 3;
System.out.println("Perfect number: " + perfectNumber);
}
}
Checkstyle warnings:
java -jar checkstyle-8.0-all.jar -c checkstyle-checks.xml Example.java
[ERROR] Example.java:4:29: Parameter arguments should be final. [FinalParameters]
[ERROR] Example.java:7:13: Variable 'perfectNumber' should be declared final. [FinalLocalVariable]
Using JavaParser, these two warnings could be fixed automatically like this (the code tries to demonstrate the idea; some parts have been ignored for now):
// AutomaticCheckstyleFix.java:
package q45326752;
import com.github.javaparser.JavaParser;
import com.github.javaparser.ast.*;
import com.github.javaparser.ast.body.*;
import com.github.javaparser.ast.expr.*;
import com.github.javaparser.ast.stmt.*;
import java.io.File;
import java.io.FileNotFoundException;
public class AutomaticCheckstyleFix {
private MethodDeclaration bestMatchMethod;
private int bestMatchMethodLineNumber;
private Statement statementByLineNumber;
public static void main(final String[] arguments) {
final String filePath = "q45326752\\input\\Example.java";
try {
new AutomaticCheckstyleFix().fixSimpleCheckstyleIssues(new File(filePath));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
private void fixSimpleCheckstyleIssues(File file) throws FileNotFoundException {
CompilationUnit javaClass = JavaParser.parse(file);
System.out.println("Original Java class:\n\n" + javaClass);
System.out.println();
System.out.println();
// Example.java:4:29: Parameter arguments should be final. [FinalParameters]
MethodDeclaration methodIssue1 = getMethodByLineNumber(javaClass, 4);
if (methodIssue1 != null) {
methodIssue1.getParameterByName("arguments")
.ifPresent(parameter -> parameter.setModifier(Modifier.FINAL, true));
}
// Example.java:7:13: Variable 'perfectNumber' should be declared final.
// [FinalLocalVariable]
Statement statementIssue2 = getStatementByLineNumber(javaClass, 7);
if (statementIssue2 instanceof ExpressionStmt) {
Expression expression = ((ExpressionStmt) statementIssue2).getExpression();
if (expression instanceof VariableDeclarationExpr) {
((VariableDeclarationExpr) expression).addModifier(Modifier.FINAL);
}
}
System.out.println("Modified Java class:\n\n" + javaClass);
}
private MethodDeclaration getMethodByLineNumber(CompilationUnit javaClass,
int issueLineNumber) {
bestMatchMethod = null;
javaClass.getTypes().forEach(type -> type.getMembers().stream()
.filter(declaration -> declaration instanceof MethodDeclaration)
.forEach(method -> {
if (method.getTokenRange().isPresent()) {
int methodLineNumber = method.getTokenRange().get()
.getBegin().getRange().begin.line;
if (bestMatchMethod == null
|| (methodLineNumber < issueLineNumber
&& methodLineNumber > bestMatchMethodLineNumber)) {
bestMatchMethod = (MethodDeclaration) method;
bestMatchMethodLineNumber = methodLineNumber;
}
}
})
);
return bestMatchMethod;
}
private Statement getStatementByLineNumber(CompilationUnit javaClass,
int issueLineNumber) {
statementByLineNumber = null;
MethodDeclaration method = getMethodByLineNumber(javaClass, issueLineNumber);
if (method != null) {
method.getBody().ifPresent(blockStmt
-> blockStmt.getStatements().forEach(statement
-> statement.getTokenRange().ifPresent(tokenRange -> {
if (tokenRange.getBegin().getRange().begin.line == issueLineNumber) {
statementByLineNumber = statement;
}
})));
}
return statementByLineNumber;
}
}
Another approach could be to create new Checkstyle plugins based on the ones you are trying to create an automatic fix for. Perhaps you have enough information available to not only give a warning but to also generate a modified version with these issues fixed.
Personally I would hesitate to have issues fixed automatically upon commit. When there are many simple fixes to be made, automation is welcome, but I would like to check these changes before committing them. Running a tool like this and checking the changes could be a very fast way to fix a lot of simple issues.
Some checks that I think could be fixed automatically:
adding static
fixing inline conditionals
FinalParameters and FinalLocalVariable: adding final
ModifierOrder: reordering modifiers (example: final static private)
NeedBraces: adding braces
I've created two groovy extension modules / methods on java.util.ArrayList(). It's all working very well inside my IDE. I use gradle to build the jar, and deploy it to a remote JVM. When it reaches the remote JVM, it fails.
Here is the extension method:
static Map sumSelectedAttributes(final List self, List attributes) {
Map resultsMap = [:]
attributes.each { attr ->
resultsMap[attr] = self.inject(0) { sum, obj ->
sum + obj[attr]
}
}
return resultsMap
Here is the code that invokes it:
outputMap[processName][iName] << kBeanList.sumSelectedAttributes([
"messageCount", "userCount", "outstandingRequests",
"cpuUsage", "memoryUsage", "threadCount", "cacheCount", "huserCount",
"manualHuserCount", "dataPointerCount", "tableHandleCount",
"jdbCacheRecordCount", "dbConnectionCount"])
Here is the error:
No signature of method: java.util.ArrayList.sumSelectedAttributes() is
applicable for argument types: (java.util.ArrayList) values:
[[messageCount, incomingConnectionsCount, outgoingConnectionsCount,
...]]
Again, it works fine in intellij with test cases. What is different on the remote JVM that would prevent this from working? Here are some things that came to my mind:
The remote JVM uses Groovy 2.3 while I'm on 2.4.5
We use a custom classloader on the remote JVM to load classes
Other than that, I could not find any other documentation about anything special I need to do to make extensions work on remote JVM's.
Any help is greatly appreciated.
Per a comment, seems like an issue with custom classloader, here is the class that handles the manipulation of a few classloaders.
class CustomLoader {
static Map loaders = [:]
static File loaderRoot = new File("../branches")
static URLClassLoader getCustomLoader(String branchName) {
if (!loaders[branchName]) {
loaders[branchName] = new URLClassLoader(getUrls(branchName))
} else {
loaders[branchName]
}
}
static URLClassLoader updateClassLoader(String branchName) {
loaders[branchName] = null
loaders[branchName] = new URLClassLoader(getUrls(branchName))
}
private static URL[] getUrls(String branchName) {
def loaderDir = new File(loaderRoot, branchName)
List<File> files = []
loaderDir.eachFileRecurse{
if (it.name.endsWith('.jar')) {
files << it
}
}
List urls = files.sort{ it.name }.reverse().collect{it.toURI().toURL()}
return urls
}
}
To manually register an extension method module you can use code similar to what is used in GrapeIvy. Because grapes have the same problem in that they make a jar visible in the wrong loader but still want to enable extension methods. The piece of code in question is this here:
JarFile jar = new JarFile(file)
def entry = jar.getEntry(ExtensionModuleScanner.MODULE_META_INF_FILE)
if (entry) {
Properties props = new Properties()
props.load(jar.getInputStream(entry))
Map<CachedClass, List<MetaMethod>> metaMethods = new HashMap<CachedClass, List<MetaMethod>>()
mcRegistry.registerExtensionModuleFromProperties(props, loader, metaMethods)
// add old methods to the map
metaMethods.each { CachedClass c, List<MetaMethod> methods ->
// GROOVY-5543: if a module was loaded using grab, there are chances that subclasses
// have their own ClassInfo, and we must change them as well!
Set<CachedClass> classesToBeUpdated = [c]
ClassInfo.onAllClassInfo { ClassInfo info ->
if (c.theClass.isAssignableFrom(info.cachedClass.theClass)) {
classesToBeUpdated << info.cachedClass
}
}
classesToBeUpdated*.addNewMopMethods(methods)
}
}
In this code file is a File representing the jar. In your case you will need to have something else here. Basically we first load the descriptor file into Properties, call registerExtensionModuleFromProperties to fill the map with MetaMethods depending on a given class loader. And that is the key part for the solution of your problem, the right class loader here is one that can load all the classes in your extension module and the groovy runtime!. After this any new meta class will know about the extension methods. The code that follows is needed only if there are already existing meta classes, you want to know about those new methods.
We are developing a large test suite which is intended to run on multiple environments, such as smoke, performance, full suite, etc. (We are currently using JUnit as the test framework.) What we are trying to achieve is annotate tests (classes or methods or both) with one or more annotations like #SmokeTest, #PerformanceTest, #AcceptanceTest and then add some test tasks in the build.gradle to run a specific selection of tests based on those annotations. The idea is very much like this one from the Gradle forum.
I know Gradle can detect JUnit tests based on JUnit annotations (see 23.12.4. Test detection in the gradle user guide). However, I cannot find out how I can leverage that capability and add some custom logics of my own. What I am looking for is something like below:
Detect the tests based on one or more given annotations (include or
exclude)
Add the detected tests into a container of some sort.
Have a test task to run tests in the container.
So, I would like to ask any guidance that you can provide to achieve that functionality. Thank you very much.
After some research, I think I have solution now. I created a demo project at github. (The name of the project is a little misleading :-]).
I also would like to paste the core logic of the solution here, which is extracted from the build.gradle in the demo project:
List testClassNames() {
File classesDir = sourceSets.test.output.classesDir
String prefix = classesDir.toString() + '/'
List names = []
classesDir.traverse {
if( it.absolutePath.endsWith( '.class' ) ) {
String name = (it.absolutePath - prefix).replaceAll( '/', '.' ) - '.class'
names << name
}
}
return names
}
ClassLoader getClassLoader() {
List urls = sourceSets.test.runtimeClasspath.collect {
it.toURI().toURL()
}
return URLClassLoader.newInstance( urls as URL[] )
}
List annotationFilter( Map map ) {
map.prefix = map?.prefix ?: '' // prefix: provide convenience for passing in annotation names
ClassLoader loader = classLoader
List result
// filter with annotations
if( !map.includes ) {
result = map?.names
} else {
result = []
map?.names.each { name ->
Class klass = loader.loadClass( name )
map?.includes.each { annotationName ->
String fullName = map.prefix + annotationName
Class<? extends Annotation> annotation = loader.loadClass( fullName ).asSubclass( Annotation )
if( klass.isAnnotationPresent( annotation ) ) {
result << name
}
}
}
}
if( result?.size() == 0 ) result = [ 'no.tests.to.run' ]
return result
}
task smoke( type: Test, description: 'Run smoke tests' ) {
doFirst {
List names = testClassNames()
List filtered = annotationFilter( names: names, includes: ['demo.Smoke'] )
println 'Running ' + filtered.size() + ' tests:\n' + filtered*.toString()*.replaceAll('^','\t').join('\n')
filter {
setIncludePatterns( filtered as String[] )
}
}
}
As you can see above, the smoke task will only execute tests annotated with #Smoke.
As mention in this answer, using Spoon and the corresponding Gradle plugin might be a more generic solution.
Edit: There also seems to be another Gradle plugin for Spoon here.
I would like to get a list of classes that are available at runtime and that match a simple name.
For example:
public List<String> getFQNs(String simpleName) {
...
}
// Would return ["java.awt.List","java.util.List"]
List<String> fqns = getFQNs("List")
Is there a library that would do this efficiently, or do I have to manually go through all classes in each classloader? What would be the correct way of doing that?
Thanks!
UPDATE
One responder asked me why I wanted to do this. Essentially, I want to implement a feature that is similar to "organize imports/auto import", but available at runtime. I don't mind if the solution is relatively slow (especially if I can then build a cache so subsequent queries become faster) and if it is a best-effort only. For example, I don't mind if I do not get dynamically generated classes.
UPDATE 2
I had to devise my own solution (see below): it uses some hints provided by the other responders, but I came to realize that it needs to be extensible to handle various environments. It is not possible to automatically traverse all classloaders at runtime so you have to rely on general and domain-specific strategies to get a useful list of classes.
I mixed the the answers from #Grodriguez and #bemace and added my own strategy to come up with a best-effort solution. This solution imitates at runtime the auto-import feature available at compile time.
The full code of my solution is here. Given a simple name, the main steps are:
Get a list of packages accessible from the current classloader.
For each package, try to load the fully qualified name obtained from package + simple name.
Step 2 is easy:
public List<String> getFQNs(String simpleName) {
if (this.packages == null) {
this.packages = getPackages();
}
List<String> fqns = new ArrayList<String>();
for (String aPackage : packages) {
try {
String fqn = aPackage + "." + simpleName;
Class.forName(fqn);
fqns.add(fqn);
} catch (Exception e) {
// Ignore
}
}
return fqns;
}
Step 1 is harder and is dependent on your application/environment so I implemented various strategies to get different lists of packages.
Current Classloader (may be useful to detect dynamically generated classes)
public Collection<String> getPackages() {
Set<String> packages = new HashSet<String>();
for (Package aPackage : Package.getPackages()) {
packages.add(aPackage.getName());
}
return packages;
}
Classpath (good enough for applications that are entirely loaded from the classpath. Not good for complex applications like Eclipse)
public Collection<String> getPackages() {
String classpath = System.getProperty("java.class.path");
return getPackageFromClassPath(classpath);
}
public static Set<String> getPackageFromClassPath(String classpath) {
Set<String> packages = new HashSet<String>();
String[] paths = classpath.split(File.pathSeparator);
for (String path : paths) {
if (path.trim().length() == 0) {
continue;
} else {
File file = new File(path);
if (file.exists()) {
String childPath = file.getAbsolutePath();
if (childPath.endsWith(".jar")) {
packages.addAll(ClasspathPackageProvider
.readZipFile(childPath));
} else {
packages.addAll(ClasspathPackageProvider
.readDirectory(childPath));
}
}
}
}
return packages;
}
Bootstrap classpath (e.g., java.lang)
public Collection<String> getPackages() {
// Even IBM JDKs seem to use this property...
String classpath = System.getProperty("sun.boot.class.path");
return ClasspathPackageProvider.getPackageFromClassPath(classpath);
}
Eclipse bundles (domain-specific package provider)
// Don't forget to add "Eclipse-BuddyPolicy: global" to MANIFEST.MF
public Collection<String> getPackages() {
Set<String> packages = new HashSet<String>();
BundleContext context = Activator.getDefault().getBundle()
.getBundleContext();
Bundle[] bundles = context.getBundles();
PackageAdmin pAdmin = getPackageAdmin(context);
for (Bundle bundle : bundles) {
ExportedPackage[] ePackages = pAdmin.getExportedPackages(bundle);
if (ePackages != null) {
for (ExportedPackage ePackage : ePackages) {
packages.add(ePackage.getName());
}
}
}
return packages;
}
public PackageAdmin getPackageAdmin(BundleContext context) {
ServiceTracker bundleTracker = null;
bundleTracker = new ServiceTracker(context,
PackageAdmin.class.getName(), null);
bundleTracker.open();
return (PackageAdmin) bundleTracker.getService();
}
Examples of queries and answers in my Eclipse environment:
File: [java.io.File, org.eclipse.core.internal.resources.File]
List: [java.awt.List, org.eclipse.swt.widgets.List, com.sun.xml.internal.bind.v2.schemagen.xmlschema.List, java.util.List, org.hibernate.mapping.List]
IResource: [org.eclipse.core.resources.IResource]
You probably cannot do this at all. There is no way for the JVM to know whether a class List in an arbitrarily named package a.b.c.d is available without attempting to load a.b.c.d.List first. You would need to test for all possible package names.
Without loading them all you could get the classpath property
String class_path = System.getProperty("java.class.path");
And then you could create a function to search the filesystem for classes in those locations. And you'd have to code it to also search inside jar files, and some of the classes may not actually be available due to incompatibilities that would only be revealed when you load them. But if you just want a best-guess of what's available, this might be viable. Maybe you should tell us why you want to do this so you can get some alternative suggestions?
Edit:
Ok, sounds like you should check out this thread and the ones linked in it: How do I read all classes from a Java package in the classpath?
In particular it appears the Spring framework does something similar, maybe you can look at that code: http://static.springsource.org/spring/docs/2.0.x/api/org/springframework/core/io/support/PathMatchingResourcePatternResolver.html