Coder Social home page Coder Social logo

jmapper-framework / jmapper-core Goto Github PK

View Code? Open in Web Editor NEW
227.0 19.0 41.0 2.12 MB

Elegance, high performance and robustness all in one java bean mapper

Home Page: http://jmapper-framework.github.io/jmapper-core

License: Apache License 2.0

Java 100.00%
annotations xml java jmapper mapper mapping api bytecode

jmapper-core's Introduction

JMapper Framework Join the chat at https://gitter.im/jmapper-framework/jmapper-core Donate

Fast as hand-written code with zero compromise.

Artifact information

Maven Central Javadocs Dependency Status

Status

Codacy Badge Build Status

Write the configuration using what you prefer: Annotation, XML or API.

Most relevant features:

especially its use is intuitive

Configuration

Below it is shown the same configuration in the three types allowed

Annotation
class Destination{                      class Source{
    @JMap
    private String id;                      private String id;
    @JMap("sourceField")                    
    private String destinationField;        private String sourceField;
    private String other;                   private String other;

    // getters and setters...               // getters and setters...
}                                       }
XML
<jmapper>
  <class name="it.jmapper.bean.Destination">
    <attribute name="id">
      <value name="id"/>
    </attribute>
    <attribute name="destinationField">
      <value name="sourceField">
    </attribute>
  </class>
</jmapper>
API
JMapperAPI jmapperAPI = new JMapperAPI()
    .add(mappedClass(Destination.class)
             .add(attribute("id")
                     .value("id"))
             .add(attribute("destinationField")
                     .value("sourceField")));

Creation

JMapper<Destination, Source> mapper;
Annotation
mapper = new JMapper<>(Destination.class, Source.class);
XML
mapper = new JMapper<>(Destination.class, Source.class, xml);
API
mapper = new JMapper<>(Destination.class, Source.class, jmapperAPI);

Usage

Source source = new Source("id", "sourceField", "other");
Destination destination = mapper.getDestination(source);

Result

destination ["id", "sourceField", null]

With JMapper we have all the advantages of dynamic mapping with the performance of static code, with 0 memory consumption.
Required java 8+

Would you like to contribute to the development of JMapper?
contact us ([email protected]) for more information.

Follow us on twitter

jmapper-core's People

Contributors

avurro avatar dependabot[bot] avatar gitter-badger avatar mksbtech avatar someshwar1 avatar waffle-iron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jmapper-core's Issues

[Question] Conversion logic to map few fields to one

I have the following case:

public class UserEntity {
    private Long userId;
    private String username;
    private String firstName;
    private String lastName;
}

public class UserDto {
    private Long id;
    private String name;
}

I want to map username, firstName and lastName fields of UserEntity to name field of UserDto by applying some conversion logic. For example:

if (firstName == null || lastName == null) {
    return username // And this will be mapped to 'name' field in UserDto
}

How this can be achievied with JMapper? I tried @JMapConversion, but it looks like it has different purpose.

Static and synthetic fields should be ignored by global mapping

When using the JGlobalMap annotation on a class which implements Serializable and has a serialVersionUID field, I get an exception complaining about there not being a getter or setter for "serialVersionUID". Similarly, when using the Jacoco plugin to measure test coverage for my code, I get an exception on classes marked with JGlobalMap complaining that there isn't a mapping for the "$jacocoData" field (a synthetic field generated by Jacoco when it instruments the bytecode). I believe this behaviour is incorrect.

My workaround for now is to put both those field names in the "excluded" attribute of the JGlobalMap annotation, but this feels like an ugly solution (especially for Jacoco - my source classes shouldn't know or care that I might want to measure their test coverage!).

JMapperCache utility

Many users have the need to manage multiple instances of JMapper, would therefore provide a useful utility about.

lambda expression in API conversions

Hi Alessandro Vurro,
I love you framework and how fast it can get , ans would be great if you can add the following ideas

1 - mix between xml configuration and annotation
digging around the code I found that xml configuration takes higher precedence, which is normal ,so what I wish for is the possiblity to mix between the two for a single class
for example I have a class called currency that I applied some annotation to it , but I need to make dynamic custom conversion so I needed to do it in xml or api style, but when I do that
all the annotation is gone , and I am forced to move all the annotation into the xml , would be great if the two can be applied.

2- mapping between destination and source list , for example
JMapper<Dest, Source> mapper = new JMapper<>(Dest.class, Source.class);
mapper.getDestinationList(source); or mapper.getDestination(// list of source and return list of destination);
it will be also great if I can control the collection type , or maybe return a configured map of key value.

3- using functional API and lambda for custom conversion.
to see this through I will apply a simple example with the following code.

public class Currency {

    String code;
    String name;
    int value;
// getters and setters
}

public class Dest {

    @JMap
    String test;
    @JMap("code")
    Currency currency;
}

public class Source {

    @JMap
    String test;
    String code;
}


public class Service {


    public Currency getCurrency(String code) {
        Currency curr = new Currency();
        curr.setCode(code);
        curr.setName("egypt");
        curr.setValue(123);

        return curr;
    }

}


    public static void main(String[] args) {


        Source source = new Source();
        source.setCode("EGypt");
        source.setTest("test  here");
        ModelMapper map =  new DefaultModelMapper();
        JMapperAPI api = new JMapperAPI();
        Service service = new Service();
        api.add(JMapperAPI.mappedClass(Dest.class).add(new Attribute("currency").value("code"))
        .add(new Conversion("conversion").from("code").to("currency").body(""
                + "System.out.println(\"trying dynamic covnersion\");"
                + "org.test.jmapper2.Service service = new org.test.jmapper2.Service();"
    +"  org.test.jmapper2.Currency cur = service.getCurrency(${source});"
                + "return cur;"))
        );
        JMapper<Dest, Source> mapper = new JMapper<>(Dest.class, Source.class, api);
        Dest d = mapper.getDestination(source);


    }

as from the example what I want to do is to custom convert between a String code , into a currency object, if I use api or xml , it will be erro prone plus , javaassist complaint a lot tell I got it right , and what if I want the vice versa of the conversion to convert from a destination to a source, so my idea is maybe if we used functional api to supply the custom conversion code then that would be great for example

Conversion convert = new Conversion("name")
convert.from("code").to("currency").body( (source) -> service.getCurrency(source.code));

I will also attach a wrapper class I made to solve this kind of problems , would love your feedback.
kindly find the google groups link for the files
https://groups.google.com/forum/#!topic/jmapper-framework/m8Dx9uMXsxM

Best regards
Farouk Elabady

XML conversion configuration leads to IllegalArgumentException

HI.

I've been playing with jmapper (I love it!). However I've hit an issue I think is probably easy to solve.

I have an XML conversion configured to help out when converting between two JAXB2 generated classes. My conversion looks a little like this (package name redacted):

<class name=".....FlightLeg">
    <global></global>
    <conversion name="durationConversion" from="legDuration" to="legDuration" type="STATIC">
        ${destination.type} result = new ${destination.type}();
        result.setMeasure(${source}.getMeasure());
        return result;
    </conversion>
</class>

When the jmapping config gets written by jmapper (version 1.3.3.1) I get:
ERROR com.googlecode.jmapper.JMapper - IllegalArgumentException: Illegal group reference

I've traced the issue to com.googlecode.jmapper.util.GeneralUtility line 389, specifically the replaceAll operation. It looks like the var.getValue() (in my case replacing the mapping placeholder) string contains a $. As the second argument for the replaceAll function is also a REGEX (see http://stackoverflow.com/questions/11913709/why-does-replaceall-fail-with-illegal-group-reference) this causes the exception. The dollar needs to be escaped, or alternatively (from the String#replaceAll javadoc):

"Note that backslashes () and dollar signs ($) in the replacement string may cause the results to be different than if it were being treated as a literal replacement string; see Matcher.replaceAll. Use Matcher.quoteReplacement(java.lang.String) to suppress the special meaning of these characters, if desired."

I hope that helps you track the error. I'd love to recommend jmapper use in my project, it's a great innovation. If you need any more data please get in touch.

ConfigHelper utility

It might come in handy a class that allows you to know the configuration at runtime

XML configuration for extended classes

I'm trying to map between two classes, however the desired destination class need to extend another class. Is this possible?

I've asked this question in more detail, here:

Thanks,
Casper

Exception when concurrent threads are trying to build the same Mapper

Ciao Alessandro!

I noticed this exception when 2 threads are trying to build the same Mapper and no mapper are available on cache (eg: app just started)

com.googlecode.jmapper.exceptions.JMapperException: javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of org/apache/catalina/loader/WebappClassLoader): attempted duplicate class definition for name: "comerawebgroupshakeThePAWcorelogicboBuddycomerawebgroupshakeThePAWcorelogicdaojpapoBuddyPO"
at com.googlecode.jmapper.config.JmapperLog.ERROR(JmapperLog.java:46)
at com.googlecode.jmapper.JMapper.(JMapper.java:418)
at com.googlecode.jmapper.JMapper.(JMapper.java:358)
at com.erawebgroup.shakeThePAW.core.logic.dao.converters.BuddyPOConverter.convertPOtoBO(BuddyPOConverter.java:95)
at com.erawebgroup.shakeThePAW.core.logic.dao.jpa.STPJPABuddyDAO.findByEmail(STPJPABuddyDAO.java:330)
at com.developerscrappad.rest.business.RESTResourceNotification.getMyPendingNotificationsCount(RESTResourceNotification.java:141)

... when the mapper is available in cache, no exceptions are rised. (eg: a second call of the same function, even from concurrent threads)

Maybe this behavior is simply "working as intended".
I solved this "non problem" by triggering Mappers caching at app start.

BTW, the chance that concurrent threads trigger the build of same mapper, in general, is very low ;-)

Personal note:
Grazie per questo fantastico contributo alla community!
A presto!

[Question] Map object to list of objects

I have the following case:

public class RegionEntity {
    private Long id;
    private String name;
}

public class RegionDto {
    private Long id;
    private String name;
}

public class RegionLegalValueDto {
    List<RegionDto> regions;
}

So, I want to map RegionEntity to a list of RegionDto in RegionLegalValueDto.

Is there an easy way to achieve that or I should map RegionEntity to RegionDto first and then put them into the list?

recursive mapping Object/List/List doesn't work

When i try to execute this mapping i obtain this error:
ConversionBodyIllegalCodeException: error in static conversion: probably is an incompatibility of signature, the expected input fields do not match with the real ones, checks the configured class.

ConversionBodyIllegalCodeException during usage conversions through JMapperAPI

Hi,
I'm trying use conversation through JMapperAPI:

final JMapperAPI api = new JMapperAPI().add(mappedClass(DTO1.class)
                .add(attribute("fieldX").value("fieldNestedList"))
                .add(conversion("conversion1")
                        .from("fieldNestedList")
                        .to("fieldX")
                        .body("return ${source}.get(0).getFieldY();")));

but got exception during excecution:

com.googlecode.jmapper.exceptions.JMapperException: com.googlecode.jmapper.exceptions.ConversionBodyIllegalCodeException: the conversion1 method contains illegal code, check the conversion code belonging to the DTO1 class. Additional information: [source error] syntax error near "UTF-8\"?>
<jmapper
 "

    at com.googlecode.jmapper.config.JmapperLog.ERROR(JmapperLog.java:46)
    at com.googlecode.jmapper.JMapper.<init>(JMapper.java:445)
    at com.googlecode.jmapper.JMapper.<init>(JMapper.java:411)
    at com.googlecode.jmapper.JMapper.<init>(JMapper.java:385)

root cause at :
ConversionHandler.java#L164

beacuse xml.getXmlPath() in this case is full xml (not path to configuration)

Thanks

How to avoid nested exception

Hello,
first of all, thank you for great library! I have one question according to nested mapping feature.

In example, I have Application class:
class Application { Category category; ... }
And Category class:
class Category { Long id; ... }

I want to map Application to ApplicationDto class:
class ApplicationDto { Long categoryId; ... }

For categoryId field I specified annotation @JMap("${category.id}") and everything works great, but I got one problem. My database in some places is inconsistent and I can't fix it in near future. Because of that sometimes I can get null in category field and this annotation at the moment of mapping throws exception. But Long type can store null and my question is - is it possible to avoid exception and provide null for categoryId if category field is also null?

Support of immutable objects

When using immutable objects - eg. immutables.org framework, default constructor is missing or private, which prevents instantiation of destination bean

API implementation

It will be allowed to write the configuration through the use of APIs,
also allowing a dynamic composition.

System.out.println in code

Dear
I foudn the console have a lot of empty lines after little investigation I found the following code

public class BasicOperation extends ASimpleOperation{

public StringBuilder mapping() {

    System.out.println("");
    Object content = setDestination(applyImplicitConversion(info.getConversionType(), destinationType(), sourceType(), getSource()));

    // add and return a mapping type control
    return this.addMappingTypeControl(write(content,newLine));

}

}

there is a system.out.println() in the code.

ClassNotMappedException with super class mapped

I'm using RelationalJMapper in my Spring Boot Project, and I have this classes.
using your example names to help understanding

class PivotI extends AbstractPivotI {
    // no attributes on this class
    // methods
}

class abstract AbstractPivotI {
    Integer id;
}

class BoI extends AbstractBoI {
    // no attributes too
    // some methods
}

class abstract AbstractBoI {
    @JMap(attributes={"id"}
          classes   ={PivotI.class })
    Integer boIfield;
}

class Magic {
    public void whereTheMagicHappens() {
        //some magic code 
        PivotI source = new PivotI(1);
        RelationalJMapper<BoI> mapper = new RelationalJMapper<BoI>(BoI.class);
        BoI destination = mapper.manyToOne(source);
        //more magic code
    }
}

When I try to use the method whereTheMagicHappens the RelationalJMapper.init() throws a ClassNotMappedException.

I'm not sure if it's a problem to you, but to use your mapper I added a attribute never used in both classes and annotated with @JMap.

Thanks for the mapper it's helping alot and if you need any information to help just ask.

Feature-request: Allow optional values for nested mapping if nested attribute is null

I would like to use a nested mapping as follows:

<attribute name="something">
  <value name="${some.thing}" />
</attribute>

This normally works but crashes when the nested attribute "some" is null.
I would like to be able to mark this kind of nested mapping optional (maybe giving a default value if the nesting contains a null value).

Maybe like this

<attribute name="something">
  <value name="${some.thing}" defaultValue="" />
</attribute>

A possible (working) workaround is:

<attribute name="something">
  <value name="${some}" />
</attribute>
<conversion name="nullIsEmptySting" to="something">
  return ${source} == null ? "null" : ${source}.getThing(); 
</conversion>

but that is annoying to write for all optional attributes.

Edit: Forgot to mention: Thanks for your work! I really enjoy using JMapper in my project!

Default value

Allowing the definition of default values.
These values are used only in case of source fields nulls.

System.out.println(""); in com.googlecode.jmapper.operations.simple.BasicOperation

This system.out prints lots of empty lines in log when the application is loaded.

public class BasicOperation extends ASimpleOperation{

public StringBuilder mapping() {

    System.out.println("");
    Object content = setDestination(applyImplicitConversion(info.getConversionType(), destinationType(), sourceType(), getSource()));

    // add and return a mapping type control
    return this.addMappingTypeControl(write(content,newLine));

}

}

mapping between nested fields

In many cases there is the need to implement a mapping between fields located on different levels, it is necessary therefore to facilitate this type of work

Janino as bytecode Generator

It would be useful to create an artifact with the implementation of the library Janino for code generation of JMapper

[Question] Map nested objects with single mapper

I have the following case:

public class Destination {
   private String destinationText;
   private NestedDestination nestedDestination;
}

public class NestedDestination {
   private String nestedDestinationData;
}

public class Source {
   @JMap(value = "destinationText", classes = Destination.class))
   private String sourceText;
   @JMap(value = "nestedDestination", classes = Destination.class))
   private NestedSource nestedSource;
}

public class NestedSource {
   @JMap(value = "nestedDestinationData", classes = NestedDestination.class))
   private String nestedSourceData;
}

The example above doesn't work due to:

com.googlecode.jmapper.exceptions.JMapperException:
com.googlecode.jmapper.exceptions.ConversionBodyIllegalCodeException: error in static
   conversion: probably is an incompatibility of signature, the expected input fields do not match
   with the real ones, checks the configured class.

I would like to map the nested object automatically using single mapper like:

JMapper<Destination, Source> mapper = new JMapper<>(Destination.class, Source.class);

without the need to create one for each nested object like:

JMapper<NestedDestination, NestedSource> mapper = new JMapper<>(NestedDestination.class, NestedSource.class);

Direct output to System.out stream

There are a System.out.println instruction in com.googlecode.jmapper.operations.simple.BasicOperation#mapping method.
This leads to lots of empty strings in output stream on mapper initialisation stage.
It's definitely not a good behaviour for a third party library.

NPE when XML path is wrong

handle the case where the path to the XML file is wrong.
For example: new JMapper(ClassA.class,ClassB.class,"wrong/path/jmapper.xml");

[Question] Map when nested objects are null.

I have the following case:

public class Source {
   private String sourceText;
   private NestedSource nestedSource;

   // Getters and Setters
}

public class NestedSource {
   private String nestedSourceData;

   // Getters and Setters
}

public class Destination {
   @JMap(value = "sourceText", classes = Source.class))
   private String destinationText;
   @JMap(value = "${nestedSource.nestedSourceData}", classes = Source.class))
   private String nestedSourceData;

   // Getters and Setters
}

Source source = new Source();
source.setSourceText("Source Text");

JMapper<Destination, Source> mapper = new JMapper<>(Destination.class, Source.class);
Destination destination = mapper.getDestination(dto, NullPointerControl.ALL, MappingType.ONLY_VALUED_FIELDS);

The example above doesn't work due to:

com.googlecode.jmapper.exceptions.JMapperException:
com.googlecode.jmapper.exceptions.NestedBeanNullException: the field lossOrDamage is null,
   error occured in mapping phase between the fields: RegisterInsuranceClaimEntity.description
   and RegisterInsuranceClaimDto.description

Is there a way to get null into nestedSourceData? I thought that NullPointerControl works even for nested objects.

Dollar character in replaceAll transformation

In relation to issue #8 , the fix has replaced special characters in the regex part of the replaceAll and not the replacement string (second argument of the replaceAll method).

This is occurring in line 389 of the GeneralUtility class. Suggest the following fix:

text = text.replaceAll(Pattern.quote(prefix+var.getKey()), Pattern.quote(var.getValue()));

Thanks.

API conversion for multiple fields doesn't work

//broken
.add(conversion("fromDoubleToString").from("latd", "lgtd").body("..."))

//works
.add(conversion("fromDoubleToString").from("latd,lgtd").body("..."))

off-by-one error in:
String com.googlecode.jmapper.util.GeneralUtility.join(String charSeparator, String... strings)

Mapping from class derived from Template to POJO

Ciao Alessandro,

I attach a tester using JMapper v1.6.0 that solicitate an exception when object of a class that specify a template class is mappet to a POJO of a simple class

In this case Boddy is User

Exception in thread "Thread-0" com.googlecode.jmapper.exceptions.JMapperException: com.googlecode.jmapper.exceptions.UndefinedMappingException: it was not possible to map the mapped id field of the BuddyVO Class with the id field of Buddy Class, please check the configuration
at com.googlecode.jmapper.config.JmapperLog.ERROR(JmapperLog.java:46)
at com.googlecode.jmapper.JMapper.(JMapper.java:445)
at com.googlecode.jmapper.JMapper.(JMapper.java:372)
at com.googlecode.jmapper.JMapper.(JMapper.java:359)
at com.blacksmithcrew.jmappertester.BuddyVOConverter.mergeBOtoVO(BuddyVOConverter.java:64)
at com.blacksmithcrew.jmappertester.BuddyVOConverter.convertBOtoVO(BuddyVOConverter.java:51)
at com.blacksmithcrew.jmappertester.JMapperTester.run(JMapperTester.java:27)
at java.lang.Thread.run(Thread.java:745)
Caused by: com.googlecode.jmapper.exceptions.UndefinedMappingException: it was not possible to map the mapped id field of the BuddyVO Class with the id field of Buddy Class, please check the configuration
at com.googlecode.jmapper.config.Error.undefinedMapping(Error.java:318)
at com.googlecode.jmapper.operations.OperationHandler.loadStructures(OperationHandler.java:168)
at com.googlecode.jmapper.generation.MapperConstructor.(MapperConstructor.java:257)
at com.googlecode.jmapper.generation.MapperBuilder.generate(MapperBuilder.java:84)
at com.googlecode.jmapper.JMapper.createMapper(JMapper.java:458)
at com.googlecode.jmapper.JMapper.(JMapper.java:440)
... 6 more

Thanl for help!
JMapperTester.jar.zip

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.