Unreferenced static inner classes treated differently by MOXy and the RI - java

Let's say I have the following two classes:
package example.model;
public class Model {
public static class Inner {}
public Other prop;
}
and
package example.model;
public class Other {
public static class Inner {}
public String prop;
}
and I create a JAXB context with JAXBContext.newInstance(example.model.Model.class).
With the default JAXB implementation from Java 6 this works without any annotations, and a generated model does not mention "inner". with EclipseLink I get a "Name collision. Two classes have the XML type with uri and name inner."
I know that making at least one of the inner classes #XmlTransient gets rid of the problem. What I would like to know is how this difference relates to the JAXB standard,
and, I guess, also if there is any other way to make MOXy ignore these classes like the default JAXB implementation does.

This appears to be a bug in EclipseLink JAXB (MOXy). We are currently working on a fix for the EclipseLink 2.3.3 and 2.4.0 streams. You can track our progress using the following link:
https://bugs.eclipse.org/374429
Once the fix is available you will be able to download a nightly build from the following link:
http://www.eclipse.org/eclipselink/downloads/nightly.php
Workaround
As you mention you can mark the static inner class with #XmlTransient.
package example.model;
public class Model {
#XmlTransient
public static class Inner {}
public Other prop;
}

Related

Inner immutable class with mapStruct

We are using Immutables with MapStruct and ran into a problem while converting an entity to dto.
#Value.Immutable
public interface ProjectDto {
String getId();
String getName();
//ProjectStatisticsDto getStatistics();
}
#Value.Immutable
public interface ProjectStatisticsDto {
Long getCount();
}
#Immutable
public interface Project extends Serializable {
#JsonProperty("_id")
String getId();
String getName();
//ProjectStatistics getStatistics();
}
#Immutable
public interface ProjectStatistics extends Serializable {
Long getCount();
}
The mapper class
#Mapper
public interface ProjectMapper {
ProjectMapper INSTANCE = Mappers.getMapper(ProjectMapper.class);
ImmProjectDto toDto(ImmProject project); // This works only when the inner model of project statistics is commented.
//ProjectDto toDto(Project project); THIS DOES NOT WORK (Error 1)
// ImmProjectDto toDto(ImmProject project); After I uncomment the inner class of project statistics then even this does not work (Error 2)
In the cases of error, the issue is exactly the same
Error 1: No implementation was created for ProjectMapper due to having a problem in the erroneous element com.xyz.ProjectDto.
Error 2: No implementation was created for ProjectMapper due to having a problem in the erroneous element com.xyz.ProjectStatisticsDto.
I checked the tests for mapstruct with immutables and there is nothing different I see https://github.com/mapstruct/mapstruct/blob/master/integrationtest/src/test/resources/immutablesBuilderTest/mapper/src/main/java/org/mapstruct/itest/immutables/Person.java.
I tried removing serialization statements but no luck. I added some verbose statements which say
Note: MapStruct: Immutables found on classpath
Note: MapStruct: Using accessor naming strategy: org.mapstruct.ap.spi.ImmutablesAccessorNamingStrategy
Note: MapStruct: Using builder provider: org.mapstruct.ap.spi.ImmutablesBuilderProvider
Note: MapStruct: Using enum naming strategy: org.mapstruct.ap.spi.DefaultEnumMappingStrategy
And this looks absolutely correct
Looking at the title of the question "Inner immutable class with mapStruct" I guess that your immutable classes are inside another class.
This is a known problem for MapStruct (see mapstruct/mapstruct#2198) that already has a PR for it and it will be fixed in the next non patch release.
In the meantime you will have to make your Immutable classes top level classes.

AspectJ #DeclareParents defaultImpl code is not used when using it as dependency

I am working with AspectJ at the moment.
I seperated AspectJ code in a dependency.
Within that dependency everything works as intended.
But as soon as I import it in another project only some functionality does not work anymore.
When using the defaultImpl of #DeclareParents, the interface is shown within the compiled code but not the default Implementation.
Here is my code to show what I mean (every code snippet is its own File):
AspectJ code:
public interface IAspect
{
String hello();
}
public class IAspectDefaultImpl implements IAspect
{
#Override
public String hello()
{
return "hello";
}
}
#Aspect
public class AspectJ
{
#DeclareParents(value = "#SomeAnnotation*", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
}
Target Class in a different project:
#SomeAnnotation
public class MyClass
{
private final int myValue;
public MyClass(final int wert)
{
this.myValue = wert;
}
public int getMyValue()
{
return myValue;
}
}
Maven throws me:
The type MyClass must implement the inherited abstract method IAspect.hello()
Which implies that it works partially.
When looking at the decompiled .class files the targeted Class does in fact implement IAspect.
The method defined in IAspectDefaultImpl is still missing tho.
My pom is set up like in this example.
I am not sure where I should start to look for errors.
Any help is apreciated.
Thanks for the MCVE. But hey, you don't use Git in order to commit 7z or ZIP archives, you ought to commit source code. I forked your project and fixed that, restructured and simplified your POMs and also fixed the main problem.
See my pull request and the commits in it for further details.
Concerning your problem, I can confirm that it occurs if you use #DeclareParents the way you do in an aspect library.
Actually, according to AspectJ maintainer Andy Clement there are certain problems with #DeclareParents when using it to provide parent interfaces + implementations in annotation style. The native AspectJ syntax via declare parents is not affected by that, but for annotation-style syntax Andy provided an alternative called #DeclareMixin, see the AspectJ manual. There he mentions that he is even considering to deprecate the defaultImpl argument of #DeclareParents in favour of #DeclareMixin.
So my bugfix (or workaround) for your problems is to actually replace
#DeclareParents(value = "#de.example.aspect.SomeAnnotation *", defaultImpl = IAspectDefaultImpl.class)
private IAspect implementedInterface;
by
#DeclareMixin("#de.example.aspect.SomeAnnotation *")
public static IAspect createIAspectImplementation() {
return new IAspectDefaultImpl();
}
This works with aspect libraries.
I will discuss with Andy about whether it makes sense to file a bug ticket for your problem or if he won't fix it anyway because there is a viable and recommended alternative.

Lombok builder inheritance with Complex Class Structure

I've read other questions regarding lombok's builder and inheritance but none of the solutions have worked. Using Lombok version 1.18.4 and Java 11.
I'm trying to inherit the parent builder while also satisfying an interface, using only immutable fields. This is my class structure:
The Code
public interface FooInterface {
String getFoo();
}
The getFoo logic is very common across all implementations, so I decided to make an Abstract helper to avoid copy-pasting the same code everywhere.
#Data
#SuperBuilder
public abstract class AbstractFoo implements FooInterface {
#Builder.Default
private final String foo = "foo";
}
And the actual Foo implementation:
#Data
#SuperBuilder
public class FooTest extends AbstractFoo {
private final String bar;
}
'Win Condition'
I would like Lombok to
Recognize fields required by the parent class.
Include those fields in the generated Builders of child classes.
In code:
final FooInterface fooTest = FooTest.builder.foo("string").bar("string").build();
assertThat("string").equals(fooTest.getFoo());
assertThat("string").equals(fooTest.getBar());
Attempted Solutions
The problem is, IntelliJ highlights the #Data annotation with this error:
Lombok needs a default constructor in the base class.
If I remove #Data from FooTest I get this error:
There is no default constructor available in base class.
So I removed the #SuperBuilder from AbstractFoo and added a manually-created constructor with all the arguments. The error persists. I've tried other things and annotation combinations, but none have worked.
I also tried -in vain- to set all AbstractFoo fields to protected final, and declare Foo implementations final themselves, which would be consistent with my business rules.
#SuperBuilder isn't supported by current version of IntelliJ IDEA plugin yet.
There's an open issue on project's Github tracker - https://github.com/mplushnikov/lombok-intellij-plugin/issues/513
Although it's targeted for 0.25 release which has been released just a few days ago -
https://github.com/mplushnikov/lombok-intellij-plugin/releases/tag/releasebuild_0.25
Issue still seems to be open and not yet implemented.
I'd suggest to just try version 0.25 and wait for the next release if it won't work.

Find class marked with annotation of a specific value

I'm using this Java Reflections API that I'm finding quite convenient so far:
https://github.com/ronmamo/reflections
Find all classes marked with a specific annotation is dead easy, however, I can't figure out how to add a filter in the scanner to retrieve classes that have that annotation configured in a certain way.
For example, if I have three classes:
#Important(level="high")
public class HighlyImportant { }
#Important(level="medium")
public class ModeratelyImportant { }
#Important(level="low")
public class NotSoImportant { }
I can get all three classes by scanning for the #Important annotation, but how do I restrict that to only #Important(level=high) ?
Thanks

Is there a Java wrapper annotation?

Trying to find a way to wraps an object, which is auto generated based on some model with lots of getters and setters. For example:
class ObjectToWrap {
public int getIntA();
public int getIntB();
... // Tons of other getters
}
I have to create a wrapper that wraps this object and use some annotation that generates methods from ObjectToWrap for me. Code looks like the following:
class Wrapper {
private ObjectToWrap obj;
public int getIntA() {
return obj.getIntA();
}
public int getIntB() {
return obj.getIntB();
}
... // Tons of other getters
}
Is there an annotation to do this? I just don't want to make the code look lengthy.
Take a look at Project Lombok which has a #Delegate annotation which does exactly what you want.
#Delegate documentation
I think you would be able to do this:
import lombok.Delegate;
class Wrapper {
//the types field in the annotation says
//to only auto generate deleagate methods
//for only the public methods in the ObjectToWrap class
//and not any parent classes if ObjectToWrap extended something
#Delegate(types = ObjectToWrap.class)
private ObjectToWrap obj;
}
If you are using the maven build infrastructure with dependency management, you could have a dependent sub-project that collects the generated sources as-is (not as code). Another sub-project could then generate real sources out of them (source code transformation) as zip, which then could be imported by maven in the main project as pre-compile target.
On that basis you could use dynamic proxy classes, or even immediate generated classes.
The only other alternative would be to use the java scripting API, and do the business in JavaScript or so. Loosing the type safeness of java and lowering the software quality.
Unfortunately the alternative of hybrid usage of another JVM language I cannot consider productive. The very nice and powerful Scala still is too wild/complex/ticklish.

Categories