DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workkloads.

Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Cutting-Edge Object Detection for Autonomous Vehicles: Advanced Transformers and Multi-Sensor Fusion
  • Writing DTOs With Java8, Lombok, and Java14+
  • Graph API for Entra ID (Azure AD) Object Management
  • A Comprehensive Guide to IAM in Object Storage

Trending

  • Evolution of Cloud Services for MCP/A2A Protocols in AI Agents
  • AI, ML, and Data Science: Shaping the Future of Automation
  • Recurrent Workflows With Cloud Native Dapr Jobs
  • Docker Model Runner: Streamlining AI Deployment for Developers
  1. DZone
  2. Coding
  3. Languages
  4. Converting Objects to Map and Back

Converting Objects to Map and Back

Learn how to convert data objects to and from Map in Java applications.

By 
Peter Verhas user avatar
Peter Verhas
DZone Core CORE ·
Jun. 21, 19 · Tutorial
Likes (1)
Comment
Save
Tweet
Share
55.1K Views

Join the DZone community and get the full member experience.

Join For Free

In large enterprise applications, sometimes, we need to convert data objects to and from Map. Usually, it is an intermediate step to a special serialization. If it is possible to use something standard, then it is better to use that, but many times, the architecture envisioned by some lead architect, the rigid environment, or some similar reason does not make it possible to use JOOQ, Hibernate, Jackson, JAX, or something similar. In such a situation, as it happened to me a few years ago, we have to convert the objects to some proprietary format being string or binary, and the first step towards that direction is to convert the object to a Map.

Eventually, the conversion is more complex than just:

Map myMap =  (Map)myObject;


Because these objects are almost never maps on their own, what we really need in the conversion is to have a Map where each entry corresponds to a field in the MyObject class. The key in the entry is the name of the field, and the value is the actual value of the field possibly converted to a Map itself.

One solution is to use reflection and reflectively read the fields of the object and create the map from it. The other approach is to create a toMap() method in the class that needs to be converted to a Map that simply adds each field to the returned map using the name of the field. This is somewhat faster than the reflection-based solution, and the code is much simpler.

When I was facing this problem in a real application a few years ago, I was so frustrated writing the primitive but numerous toMap() methods for each data object that I created a simple reflection-based tool that to do it just for any class we wanted. Did it solve the problem? No.

This was a professional environment where not only the functionality matters but also the quality of the code and the quality of my code, judged by my fellow programmers, was not matching. They argued that the reflection-based solution is complex and in case it becomes part of the code base then the later joining average developers will not be able to maintain it. Well, I had to admit that they were correct. In a different situation, I would have said that the developer has to learn reflection and programming in Java on a level that is needed by the code. In this case, however, we were not speaking about a specific person, but rather somebody who comes and joins the team in the future, possibly sometime when we have already left the project. This person was assumed to be an average developer, which seemed to be reasonable as we did not know anything about this person. In that sense, the quality of the code was not good, because it was too complex. The quorum of the developer team decided that maintaining the numerous manually crafted toMap() method was going to be cheaper than finding senior and experienced developers in the future.

To be honest, I was a bit reluctant to accept their decision, but I accepted it even though I had the possibility to overrule it based simply on my position in the team. I tend to accept the decisions of the team even if I do not agree with that, but only if I can live with those decisions. If a decision is dangerous, terrible, and threatens the future of the project, then we have to keep discussing the details until we get to an agreement.

Years later, I started to create Java::Geci as a side project that you can download from http://github.com/verhas/javageci.

Java::Geci is a code generation tool that runs during the test phase of the Java development life cycle. Code generation in Java::Geci is a “test.” It runs the code generation, and in case all the generated code stays put, then the test was successful. In case anything in the code base changed in a way that causes the code generator to generate different code than before, and thus the source code changes, then the test fails. When a test fails, you have to fix the bug and run the build, including tests, again. In this case, the test generates the new, by now fixed, code, therefore, all you have to do is only to run the build again.

When developing the framework, I created some simple generators to generate equals() and hashCode(), setters and getters, a delegator generator, and finally, I could not resist but I created a general purpose toMap() generator. This generator generates code that converts the object to Map just as we discussed before and also the fromMap() that I did not mention before, but fairly obviously also needed.

 Java::Geci generators are classes that implement the Generator interface. The Mapper generator does that extending the abstract class AbstractJavaGenerator. This lets the generator throw any exception easing the life of the generator developer, and also it already looks up the Java class, which was generated from the currently processed source. The generator has access to the actual Class object via the parameter klass and the same time to the source code via the parameter source, which represents the source code and provides methods to create Java code to be inserted into it.

The third parameter global is something like a map holding the configuration parameters that the source code annotation @Geci defines.

package javax0.geci.mapper;

import ...

public class Mapper extends AbstractJavaGenerator {

...

    @Override
    public void process(Source source, Class<?> klass, CompoundParams global)
                                                             throws Exception {
        final var gid = global.get("id");
        var segment = source.open(gid);
        generateToMap(source, klass, global);
        generateFromMap(source, klass, global);

        final var factory = global.get("factory", "new {{class}}()");
        final var placeHolders = Map.of(
                "mnemonic", mnemonic(),
                "generatedBy", generatedAnnotation.getCanonicalName(),
                "class", klass.getSimpleName(),
                "factory", factory,
                "Map", "java.util.Map",
                "HashMap", "java.util.HashMap"
        );
        final var rawContent = segment.getContent();
        try {
            segment.setContent(Format.format(rawContent, placeHolders));
        } catch (BadSyntax badSyntax) {
            throw new IOException(badSyntax);
        }
    }


The generator itself only calls the two methods generateToMap() and generateFromMap(), which generate, as the names imply the toMap() and fromMap() methods into the class.

Both methods use the source generating support provided by the Segment class, and they also use the templating provided by Jamal. It is also important to note that the fields are collected calling the reflection tools method getAllFieldsSorted(), which returns all the field the class has in a definitive order that does not depend on the actual JVM vendor or version.

private void generateToMap(Source source, Class<?> klass, CompoundParams global) throws Exception {
    final var fields = GeciReflectionTools.getAllFieldsSorted(klass);
    final var gid = global.get("id");
    var segment = source.open(gid);
    segment.write_r(getResourceString("tomap.jam"));
    for (final var field : fields) {
        final var local = GeciReflectionTools.getParameters(field, mnemonic());
        final var params = new CompoundParams(local, global);
        final var filter = params.get("filter", DEFAULTS);
        if (Selector.compile(filter).match(field)) {
            final var name = field.getName();
            if (hasToMap(field.getType())) {
                segment.write("map.put(\"%s\", %s == null ? null : %s.toMap0(cache));", field2MapKey(name), name, name);
            } else {
                segment.write("map.put(\"%s\",%s);", field2MapKey(name), name);
            }
        }
    }
    segment.write("return map;")
            ._l("}\n\n");
}


The code selects only the fields that are denoted by the filter expression.

Object (computer science)

Published at DZone with permission of Peter Verhas, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Cutting-Edge Object Detection for Autonomous Vehicles: Advanced Transformers and Multi-Sensor Fusion
  • Writing DTOs With Java8, Lombok, and Java14+
  • Graph API for Entra ID (Azure AD) Object Management
  • A Comprehensive Guide to IAM in Object Storage

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!