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
Refcards Trend Reports
Events Video Library
Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
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

Integrating PostgreSQL Databases with ANF: Join this workshop to learn how to create a PostgreSQL server using Instaclustr’s managed service

Mobile Database Essentials: Assess data needs, storage requirements, and more when leveraging databases for cloud and edge applications.

Monitoring and Observability for LLMs: Datadog and Google Cloud discuss how to achieve optimal AI model performance.

Automated Testing: The latest on architecture, TDD, and the benefits of AI and low-code tools.

Related

  • Embracing Reactive Programming With Spring WebFlux
  • Spring Boot Annotations: Behind the Scenes and the Self-Invocation Problem
  • Comparing ModelMapper and MapStruct in Java: The Power of Automatic Mappers
  • A Guide to Enhanced Debugging and Record-Keeping

Trending

  • Best Practices for Writing Clean Java Code
  • REST vs. Message Brokers: Choosing the Right Communication
  • Microservices With Apache Camel and Quarkus (Part 5)
  • Mastering Persistence: Why the Persistence Layer Is Crucial for Modern Java Applications
  1. DZone
  2. Coding
  3. Frameworks
  4. Just What Are Spring 3.2 Matrix Variables? - Part 2: The Code

Just What Are Spring 3.2 Matrix Variables? - Part 2: The Code

Roger Hughes user avatar by
Roger Hughes
·
Apr. 19, 13 · Interview
Like (0)
Save
Tweet
Share
10.17K Views

Join the DZone community and get the full member experience.

Join For Free

My last blog on Spring's support for Matrix Variables concentrated on explaining what they were and why you'd want to use them. Having sorted out the what and the why, this blog is all about the how and how you use them. I also gave several examples of Matrix URIs and so, it seems good idea to demonstrate some code that processes a couple of them.

The examples were

http://localhost:8080/spring_3_2/matrixvars/stocks;BT.A=276.70,+10.40,+3.91;AZN=236.00,+103.00,+3.29;SBRY=375.50,+7.60,+2.07

http://localhost:8080/spring_3_2/matrixvars/stocks;BT.A=276.70,+10.90,+3.91;AZN=236.00,+103.00,+3.29;SBRY=375.50,+7.60,+2.07/account;name=roger;number=105;location=stoke-on-trent,uk

As you'd expect, in writing code to handle Matrix Variables, the Guys at Spring are building upon the existing Spring MVC framework by introducing the new @MatrixVariable annotation. This is used to annotate request handler method arguments so that Spring can inject the relevant bits of the matrix uri. @MatrixVariable has four arguments: value, defaultValue, pathVar and required, all of which are fully explained in Springs javadocs.

And so to some code... If you remember in my last blog on this subject, the scenario I chose was one that deals with processing a bunch of share/stock prices and the sample application, available on Github, takes a Matrix URI, chops it up and adds it to a Model for a JSP to display.

In writing the code, the first thing to do is to create a new controller to process the URIs...

@Controller
@RequestMapping(value = "/matrixvars")
public class MatrixVariableController {

  private static final Logger logger = LoggerFactory.getLogger(MatrixVariableController.class);
}

n the code I've added a class level @RequestMapping annotation, which contains the first chunk of my URIs: matrixvars. This is a useful thing to do as it directs all URIs that contain the value 'matrixvar' as the first path element to this controller and saves a lot of duplication.

The next thing to do is to add some code to this class that deals with the first URI:

http://localhost:8080/spring_3_2/matrixvars/stocks;BT.A=276.70,+10.40,+3.91;AZN=236.00,+103.00,+3.29;SBRY=375.50,+7.60,+2.07

The first request handler method is:

@RequestMapping(value = "/{stocks}", method = RequestMethod.GET)
  public String showPortfolioValues(@MatrixVariable Map<String, List<String>> matrixVars, Model model) {

    logger.info("Storing {} Values which are: {}", new Object[] { matrixVars.size(), matrixVars });

    List<List<String>> outlist = map2List(matrixVars);
    model.addAttribute("stocks", outlist);

    return "stocks";
  }

  private List<List<String>> map2List(Map<String, List<String>> stocksMap) {

    List<List<String>> outlist = new ArrayList<List<String>>();

    Collection<Entry<String, List<String>>> stocksSet = stocksMap.entrySet();

    for (Entry<String, List<String>> entry : stocksSet) {

      List<String> rowList = new ArrayList<String>();

      String name = entry.getKey();
      rowList.add(name);

      List<String> stock = entry.getValue();
      rowList.addAll(stock);
      outlist.add(rowList);
    }

    return outlist;
  }

ooking at the @RequestMapping annotation you can see that I've assigned it a value of /{stocks}. This, when combined with the class level @RequestMapping annotation, will instruct Spring to map any matching requests to this method. The text inside the curly braces, {stocks}, indicates that this part of the URI can be parsed and injected into the appropriate method argument.

Next, take a look at the @MatrixVariable annotation. This sits neatly in front of the argument into which I want the stock data injected; however, the slightly tricky thing here is getting the argument type right. If you get this wrong then you'll simply get a ClassCastException when you try to use your data. When the input data is of the form:

A=B,C,D

or

A=B,C,D;W=X,Y,Z

...then the type is Map<String,List<String>>, where the keys are A and W and their respective values are B,C,D and X,Y,Z.

Hence, given the URI above, the map argument will contain....

{BT.A=[276.70, +10.40, +3.91], AZN=[236.00, +103.00, +3.29], SBRY=[375.50, +7.60, +2]}

That's the important bit over with, the rest of the method is very straight forward in that is simply converts the input map into a list and adds it to the model for the JSP (not shown here) to display. Note that this isn't very useful code, so don't pay that much attention to it and besides I'm not fond of embedding collections within collections - it doesn't seem like a good idea.

Moving on, I'll now take a look at the next URI. Notice that I've purposely made this similar to the first, with the only difference being the addition of the user's account details:

http://localhost:8080/spring_3_2/matrixvars/stocks;BT.A=276.70,+10.90,+3.91;AZN=236.00,+103.00,+3.29;SBRY=375.50,+7.60,+2.07/account;name=roger;number=105;location=stoke-on-trent,uk

This URI is mapped to the following method:
@RequestMapping(value = "/{stocks}/{account}", method = RequestMethod.GET)
  public String showPortfolioValuesWithAccountInfo(@MatrixVariable(pathVar = "stocks") Map<String, List<String>> stocks,
      @MatrixVariable(pathVar = "account") Map<String, List<String>> accounts, Model model) {

    List<List<String>> stocksView = map2List(stocks);
    model.addAttribute("stocks", stocksView);

    List<List<String>> accountDetails = map2List(accounts);
    model.addAttribute("accountDetails", accountDetails);

    return "stocks";
  }
In this case the full path description is /matrixvars/{stocks}/{account}. I guess that this simply tells Spring to look out for /matrixvars, followed by a '/' followed by anything, followed by a '/', followed by anything, when it does its mapping.

In this case there are two @MatrixVariable annotations to which I've added the annotation's pathVar argument supplying values stocks and accounts. These neatly label where the matrix variable values need injecting into the method arguments.

The final point to remember is that Matrix Variable are incredibly flexible; there are another three arguments to the @MatrixVaraible annotation that I've not considered here; however, the general procedure is the same in every case: take the URI, figure out what the different matrix variables are, design a request handler and map the URI's matrix variables to your methods arguments - taking care to ensure that you get the argument type correct.


The full sample code for this blog is available on Github: https://github.com/roghughe/captaindebug/tree/master/spring-3.2



Matrix (protocol) Spring Framework

Published at DZone with permission of Roger Hughes, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Embracing Reactive Programming With Spring WebFlux
  • Spring Boot Annotations: Behind the Scenes and the Self-Invocation Problem
  • Comparing ModelMapper and MapStruct in Java: The Power of Automatic Mappers
  • A Guide to Enhanced Debugging and Record-Keeping

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • 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: