jaxb.index and nested classes (and OSGi) - java

When I try to refer to nested classes within my jaxb.index file, an exception is thrown during serialization. How can this be avoided?
This is in an Eclipse RCP application. The classes causing the exception are in a different plug-in than the one that creates the JAXB context and initiates serialization. The classes are in one of the plug-in's exported packages.
The class structure looks like this (names have been changed):
#XmlRootElement(name="foo")
#XmlAccessorType (XmlAccessType.FIELD)
public class Foo extends AbstractFoo {
...
#XmlRootElement(name="fooMetric")
#XmlAccessorType (XmlAccessType.FIELD)
public static class FooMetric implements IFooMetric {
...
}
}
The jaxb.index file contains these:
Foo
Foo.FooMetric
During serialization, the exception says to use "OuterClass.InnerClass" -- which I'm doing.
javax.xml.bind.JAXBException: error loading class "Foo.FooMetric" listed in com/mypackage/jaxb.index, make sure that entries are accessable on CLASSPATH and of the form "ClassName" or "OuterClass.InnerClass", not "ClassName.class" or "fully.qualified.ClassName"
- with linked exception:
[java.lang.ClassNotFoundException: com.mypackage.Foo.FooMetric]
The javadocs ("Format for jaxb.index") also suggests that jaxb.index can contain entries of the form OuterClass.InnerClass.
Constraints on class name occuring in a jaxb.index file are:
Must not end with ".class".
Class names are resolved relative to package containing jaxb.index file. Only classes occuring directly in package containing jaxb.index file are allowed.
Fully qualified class names are not allowed. A qualified class name,relative to current package, is only allowed to specify a nested or inner class.
However, this does not appear to work. What will make it work?

The solution I found (by trial and error) was to use OuterClass$InnerClass in jaxb.index instead of OuterClass.InnerClass. This allows serialization to complete successfully.
However, I haven't found any authoritative source that recommends this.
[I'm posting this solution per stackoverflow guidelines, but would love to see and accept a better answer.]

Related

Access Java class defined in a file with many classes from Kotlin

I have a package which contains a public Kotlin class and a Java file with many package-private top-level classes like so:
com.example.mypackage
- KotlinClass.kt
- JavaClasses.java
-- Class1
-- Class2
-- ...
If I try to access any class from JavaClasses in KotlinClass I get Unresolved reference error. Is it possible to access these classes?
I cannot change JavaClasses.java because it's generated.
It should be possible to access these classes with the setup that you described, the only time I get a an Unresolved reference error is when there are errors within the java file. Perhaps because JavaClasses.java is generated it doesn't have the correct package declaration at the top of the file, which in your case should be package com.example.mypackage;

How to instrument/rebase inner classes with Byte Buddy?

Goal
I would like to create a plug-in wrapper to embed a Java code that will let me enable/disable methods annotated with JUnit5 Before* and After* annotations at runtime as well as handle in similar manner JUnit5 extensions (the ExtendWith annotation).
I chose ByteBuddy as primary instrumentation library.
I created a github repo here: https://github.com/azewiusz/bytebuddy_examples where I describe the idea in more detail.
Question
The problem is that I cannot get instrumentation working for inner classes.
I keep getting two exceptions:
Caused by: java.lang.IllegalStateException: Failed to invoke proxy for
public abstract java.lang.reflect.AnnotatedElement
net.bytebuddy.description.method.MethodDescription$InDefinedShape$AbstractBase$Executable.getAnnotatedReceiverType(java.lang.Object)
preceded by
Caused by: java.lang.IncompatibleClassChangeError
tests.TestSetWithInnerClasses and
tests.TestSetWithInnerClasses$HelperTestFilteredOutExtendWithInnerClass
disagree on InnerClasses attribute
A test class that reproduces is here:
https://github.com/azewiusz/bytebuddy_examples/blob/master/src/test/java/tests/CoreInstrumentationTest.java
-> Look there for test2
It fails at this transformation:
final Class strippedOffExtendWithAnnotation = filterOutJUnit5ExtendWithAnnotation(
testClass, classLoader );
Class beforeAll = stagedTypeTransform( strippedOffExtendWithAnnotation,
new ByteBuddy().rebase( strippedOffExtendWithAnnotation,
ClassFileLocator.ForClassLoader.of( classLoader ) )
.name( testClass.getName() + "BeforeAll" )
.method( ElementMatchers
.isAnnotatedWith( BeforeAll.class ) )
.intercept( MethodDelegation.to( InterceptorForBeforeAllAnnotation.class ) ).make() );
I found following that seem to refer to similar problem:
How to access type annotations on a receiver type's parameters
https://github.com/raphw/byte-buddy/issues/83
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=7003595 (seems
to be partially related)
But haven't found yet an exact solution.
Instrumenting inner classes is tricky. Java classes contain so-called inner class attributes that describe Java class properties that compiled Java classes cannot represent. For example, a compiled Java class cannot be private, but you would still want to see this modifier for the inner class when using reflection.
You can consider to make your new class a top-level class by using topLevelType() in the DSL. You should also consider noNestMate() to avoid clashes there.

Java : Interface in a class is not accessible while importing

I am using the maven dependency hive-hcatalog-core in my program
and this jar present in the project maven dependencies, with the interface (as in the image-top).
The interface ICacheableMetaStoreClient , though present the class, is NOT resolvable from import org.apache.hive.hcatalog.common. (image -bottom)
consequently, while doing a spark-submit, I am getting the exception :
com.google.common.util.concurrent.UncheckedExecutionException:
java.lang.IllegalArgumentException: interface
org.apache.hive.hcatalog.common.HiveClientCache$ICacheableMetaStoreClient
is not visible from class loader
What do I need to do for this to be visible from the program class path.
Lets look at the code:
class HiveClientCache {..}
The HiveClientCache has only package level visibility and it along with ICacheableMetaStoreClientwont wont be available for import outside of that package (this includes in your code).
Now lets look at ICacheableMetaStoreClient:
#InterfaceAudience.Private
public interface ICacheableMetaStoreClient extends IMetaStoreClient {....}
The interface is public but has annotation on it that makes the Hive/Hadoop additional preprocessing to check object type and throw IllegalArgumentException.
Here is the JavaDoc for InterfaceAudience:
Annotation to inform users of a package, class or method's intended
audience. Currently the audience can be InterfaceAudience.Public,
InterfaceAudience.LimitedPrivate or InterfaceAudience.Private. All
public classes must have InterfaceAudience annotation.
Public classes that are not marked with this annotation must be considered by default as InterfaceAudience.Private.
External applications must only use classes that are marked InterfaceAudience.Public. Avoid using non public classes as these
classes could be removed or change in incompatible ways.
Hadoop projects must only use classes that are marked InterfaceAudience.LimitedPrivate or InterfaceAudience.Public
Methods may have a different annotation that it is more restrictive compared to the audience classification of the class. Example: A class
might be InterfaceAudience.Public, but a method may be
InterfaceAudience.LimitedPrivate

web service - client classes

The web service that I implemented is up and running, when I try to run the client I get the following error with regard to the classes that were generated using wsimport,
Caused by: java.security.PrivilegedActionException: com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 4 counts of IllegalAnnotationExceptions
Two classes have the same XML type name "{http://server.agency.hw2/}userJoined". Use #XmlType.name and #XmlType.namespace to assign different names to them.
this problem is related to the following location:
at hw2.chat.backend.main.generatedfromserver.UserJoined
at public javax.xml.bind.JAXBElement hw2.chat.backend.main.generatedfromserver.ObjectFactory.createUserJoined(hw2.chat.backend.main.generatedfromserver.UserJoined)
at hw2.chat.backend.main.generatedfromserver.ObjectFactory
this problem is related to the following location:
at ChatCompany.BackendChatServer.hw2.chat.backend.main.generatedfromserver.UserJoined
Two classes have the same XML type name "{http://server.agency.hw2/}userJoinedResponse". Use #XmlType.name and #XmlType.namespace to assign different names to them.
this problem is related to the following location:
at hw2.chat.backend.main.generatedfromserver.UserJoinedResponse
at public javax.xml.bind.JAXBElement hw2.chat.backend.main.generatedfromserver.ObjectFactory.createUserJoinedResponse(hw2.chat.backend.main.generatedfromserver.UserJoinedResponse)
But I can't figure out what exactly is meant by the error. I am assuming I need to change something in annotations in these classes as pointed out by the compiler:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "userJoinedResponse")
public class UserJoinedResponse {
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "userJoined", propOrder = {
"arg0"
})
public class UserJoined {
could someone please point out why there's a name collision and what annotations I need to change?
thanks
My teacher has suggested (among other reasons) that maybe there is something wrong with the way i ran the wsimport utility, so I regenerated the client class files using wsimport and the problem was solved. it might have been that I didn't specify the package name at the beginning and did it manually first time but I am uncertain.
I got the same exception. The reason is a similarity of names both classes. When you have class with name UserJoined during wsdl generation process JAXB generate element with name UserJoinedResponse (see your wsdl file).
And the you try to add another class with the same name (UserJoinedResponse). So just rename UserJoinedResponse class or annotate it as mentioned in the exception.

Defining classes in Java files

I have found one error in my Java program:
The public type abc class must be defined in its own class
How can I resolve this error? I am using Eclipse. I am new to Java programming.
Each source file must contain only one public class. A class named ClassName should be in a file named ClassName.java, and only that class should be defined there.
Exceptions to this are anonymous and inner classes, but understanding you are a beginner to Java, that is an advanced topic. For now, keep one class per file.
Answering your addition: it is OK to inherit classes and that's totally fine. This does not matter, each class should still have its own file.
Public top-level classes (i.e. public classes which aren't nested within other classes) have to be defined in a file which matches the classname. So the code for class "Foo" must live in "Foo.java".
From the language specification, section 7.6:
When packages are stored in a file system (ยง7.2.1), the host system may choose to enforce the restriction that it is a compile-time error if a type is not found in a file under a name composed of the type name plus an extension (such as .java or .jav) if either of the following is true:
The type is referred to by code in other compilation units of the package in which the type is declared.
The type is declared public (and therefore is potentially accessible from code in other packages).
This rule, which doesn't have to be followed by compilers, is pretty much universally adhered to.
Ok, maybe an example will help.
In file MySuperClass.java:
public class MySuperClass {
// whatever goes here
}
public class MySubClass1 extends MySuperClass {
// compile error: public class MySubClass1 should be in MySubClass1.java
}
class MySubClass2 extends MySuperClass {
// no problem (non-public class does not have to be in a file of the same name)
}
In file MySubClass3.java:
public class MySubClass3 extends MySuperClass {
// no problem (public class in file of the same name)
}
Does that make things clearer?
A public class with the name of "abc" must be in a file called abc.java
You can create a new class an a existing file if it's private, but you should not do this.
Create one file per class.
Eclipse does that for you, if you create a new class.
For programming Java, you have to understand the construct of classes, packages and files. Even if Eclipse helps you, you have to know it for yourself. So start reading Java books or tutorials!

Categories

Resources