J Notes

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 19

uk 0538

https://thoughts-on-java.org/tutorials/

The java string intern() method returns the interned string. It returns the
canonical representation of string.

It can be used to return string from memory, if it is created by new keyword. It


creates exact copy of heap string object in string constant pool.

VirtualMachineError or StackOverflowError

throwable
- error
- exception
- checked (compile time)
- unchecked (runtime)

checked exception
-> compile time exception
unchecked exception
-> runtime exception

Rule: By default, Checked Exceptions are NOT forwarded in


calling chain (propagated). if specified in throws checked exceptions can be
forwarded

throws used to declare exceptions


- only unchecked exception should be declared

If the superclass method does not declare an exception


If the superclass method does not declare an exception, subclass overridden
method cannot declare the checked exception but it can declare unchecked exception.
If the superclass method declares an exception
If the superclass method declares an exception, subclass overridden method
can declare same, subclass exception or no exception but cannot declare parent
exception.

Rule: If the superclass method declares an exception, subclass overridden method


can declare same, subclass exception or no exception but cannot declare parent
exception.

Primetive vs wrapper

Caution is required when using the ternary operator with boxed types and null. From
the language specification:

If one of the second and third operands is of primitive type T, and the type of the
other is the result of applying boxing conversion to T, then the type of the
conditional expression is T.

- for wrapper always use .equals() method to compare value otherwise always false
as it is object.
https://dzone.com/articles/how-does-spring-transactional

https://docs.oracle.com/javase/6/docs/api/java/lang/ThreadLocal.html

datatypes
primitive vs wrapper

typeconverstion
string operation
.contains("")
.compareTo("") lexicographically compare
.equal
.substring(start, end)
date operation

autoboxing
marshaling
seralizing

collections
- list, set, map
- basics
- operations

An abstract class cannot be instantiated directly, i.e. object of such class cannot
be created directly using new keyword. An abstract class can be instantiated either
by concrete subclass, or by defining all the abstract method along with the new
statement. A concrete class can be instantiated directly, using a new keyword.

JPA
- hibernet
--> all toOne are egar
--> all toMany are lazy by default

=> owner entity is one having field for foriegn key


=> shared primary is when two table have uses have same value as primary key

@OneToOne
Use @PrimaryKeyJoinColumn for associated entities sharing the same
primary key.
Use @JoinColumn & @OneToOne mappedBy attribute when foreign key is held
by one of the entities.
Use @JoinTable and mappedBy entities linked through an association
table.
Persist two entities with shared key using @MapsId

@ManyToOne
Use @JoinColumn when foreign key is held by one of the entities.
Use @JoinTable for entities linked through an association table.
@OneToMany
Use mappedBy attribute for bi-directional associations with ManyToOne
being the owner.
OneToMany being the owner or unidirectional with foreign key - try to
avoid such associations but can be achieved with @JoinColumn
@JoinTable for Unidirectional with association table
@ManyToMany
Use @JoinTable for entities linked through an association table.
Use mappedBy attribute for bi-directional association.

Jdbc

logs

spring boot
- anotations
- transactiona management
-

memeory management

deployment

kubernatice
kibanna

suggestions to improove performance


- hibernate

https://thoughts-on-java.org/5-common-hibernate-mistakes-that-cause-dozens-of-
unexpected-queries/

===> all many to one are egar by default so need to mark as lazy when required
===> for lazy association, runs extra quries so use LEFT JOIN FETCH relation
instead when required
===> for list relation all elements are removed & and addded for any changes, so
mark attribute are Set not List
===> removing child eith CascadeType.Remove maked individual quries
===> updating and removing in bulk using In makes individual quries

following makes individual qury for all ids


TypedQuery<Author> query = em.createQuery("SELECT a FROM Author a WHERE id IN
(:ids)", Author.class);
query.setParameter("ids", ids);
List<Author> authors = query.getResultList();

for (Author a : authors) {


em.remove(a);
}

need to first flush and clear context

em.flush();
em.clear();

// Remove all entities referenced in the List ids variable


Query query = em.createQuery("DELETE Author a WHERE id IN (:ids)");
query.setParameter("ids", ids);
query.executeUpdate();

https://www.baeldung.com/spring-core-annotations

Spring Core Annotations

@Autowired
@Bean
@Bean
Engine engine() {
return new Engine();
}

@Qualifier
@Autowired
Biker(@Qualifier("bike") Vehicle vehicle) {
this.vehicle = vehicle;
}

@Required
void setColor(String color) {
this.color = color;
}

<bean class="com.baeldung.annotations.Bike">
<property name="color" value="green" />
</bean>

@DependsOn("engine")
class Car implements Vehicle {}

@Configuration
@Lazy
class VehicleFactoryConfig {

@Bean
@Lazy(false)
Engine engine() {
return new Engine();
}
}

@Primary
class Car implements Vehicle {}

@Component
@Scope("prototype")
class Engine {}
@Profile("sportDay")
class Bike implements Vehicle {}

@Import(VehiclePartSupplier.class)
class VehicleFactoryConfig {}

https://www.baeldung.com/spring-mvc-annotations

WEB anotaions

@RequestMapping
path, or its aliases, name, and value: which URL the method is mapped to
method: compatible HTTP methods
params: filters requests based on presence, absence, or value of HTTP
parameters
headers: filters requests based on presence, absence, or value of HTTP
headers
consumes: which media types the method can consume in the HTTP request body
produces: which media types the method can produce in the HTTP response body

Moreover, @GetMapping, @PostMapping, @PutMapping, @DeleteMapping, and @PatchMapping


are different variants of @RequestMapping with the HTTP method already set to GET,
POST, PUT, DELETE, and PATCH respectively.
These are available since Spring 4.3 release.

@PostMapping("/save")
void saveVehicle(@RequestBody Vehicle vehicle) {

@RequestMapping("/{id}")
Vehicle getVehicle(@PathVariable("id") long id) {
// ...
}

@RequestMapping
Vehicle getVehicleByParam(@RequestParam("id") long id) {
// ...
}

If we mark a request handler method with @ResponseBody, Spring treats the result of
the method as the response itself:

@ResponseBody
@RequestMapping("/hello")
String hello() {
return "Hello World!";
}

With this annotation, we can declare a custom error handler method. Spring calls
this method when a request handler method throws any of the specified exceptions.

@ExceptionHandler(IllegalArgumentException.class)
void onIllegalArgumentException(IllegalArgumentException exception) {
// ...
}

We can specify the desired HTTP status of the response if we annotate a request
handler method with this annotation. We can declare the status code with the code
argument, or its alias, the value argument

@ExceptionHandler(IllegalArgumentException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
void onIllegalArgumentException(IllegalArgumentException exception) {
// ...
}

@Controller

The @RestController combines @Controller and @ResponseBody.

@ModelAttribute
With this annotation we can access elements that are already in the model of an
MVC @Controller, by providing the model key:

@PostMapping("/assemble")
void assembleVehicle(@ModelAttribute("vehicle") Vehicle vehicleInModel) {
// ...
}

@CrossOrigin enables cross-domain communication for the annotated request handler


methods:

https://www.baeldung.com/spring-boot-annotations

Spring boot annotations

@SpringBootApplication
@SpringBootApplication encapsulates @Configuration, @EnableAutoConfiguration,
and @ComponentScan annotations with their default attributes.

@ConditionalOnClass and @ConditionalOnMissingClass

Using these conditions, Spring will only use the marked auto-configuration
bean if the class in the annotation’s argument is present/absent:

@Configuration
@ConditionalOnClass(DataSource.class)
class MySQLAutoconfiguration {
//...
}

@ConditionalOnBean and @ConditionalOnMissingBean


We can use these annotations when we want to define conditions based on the
presence or absence of a specific bean:
@ConditionalOnProperty

@Bean
@ConditionalOnProperty(
name = "usemysql",
havingValue = "local"
)
DataSource dataSource() {
// ...
}

@ConditionalOnResource

@ConditionalOnResource(resources = "classpath:mysql.properties")
Properties additionalProperties() {
// ...
}

@ConditionalOnWebApplication

@Bean
@ConditionalOnExpression("${usemysql} && ${mysqlserver == 'local'}")
DataSource dataSource() {
// ...
}

@Conditional(HibernateCondition.class)
Properties additionalProperties() {
//...
}

https://www.baeldung.com/spring-data-annotations

Common Spring Data Annotations

@Transactional
want to configure the transactional behavior of a method

@Transactional
void pay() {}

@NoRepositoryBean
interface MyUtilityRepository<T, ID extends Serializable> extends CrudRepository<T,
ID> {
Optional<T> findById(ID id);
}

@Query("FROM Person p WHERE p.name = :name")


Person findByName(@Param("name") String name);

@Id
Long id;

We can use this annotation to mark a field in a model class as transient.


Hence the data store engine won’t read or write this field’s value:

@Transient
int age;

With these annotations, we can audit our model classes: Spring automatically
populates the annotated fields with the principal who created the object, last
modified it, and the date of creation, and last modification:

@CreatedBy
User creator;

@LastModifiedBy
User modifier;

@CreatedDate
Date createdAt;

@LastModifiedDate
Date modifiedAt;

Supports JPQL & SQL


@Query("FROM Person p WHERE p.name = :name")
Person findByName(@Param("name") String name);

@Query(value = "SELECT AVG(p.age) FROM person p", nativeQuery = true) //


Need to make nativeQuery true
int getAverageAge();

We can configure the lock mode when we execute a repository query method
@Lock(LockModeType.NONE)
@Query("SELECT COUNT(*) FROM Person p")
long getPersonCount();

READ
WRITE
OPTIMISTIC
OPTIMISTIC_FORCE_INCREMENT
PESSIMISTIC_READ
PESSIMISTIC_WRITE
PESSIMISTIC_FORCE_INCREMENT
NONE

To use JPA repositories, we have to indicate it to Spring. We can do this


with @EnableJpaRepositories.

Note, that we have to use this annotation with @Configuration


For the methods we get out-of-the-box like findAll(Sort) or the ones that are
generated by parsing method signatures, we can only use object properties to define
our sort:
userRepository.findAll(new Sort(Sort.Direction.ASC, "name"));

userRepository.findAllUsers(JpaSort.unsafe("LENGTH(name)"));

When the @Query annotation uses native SQL, then it’s not possible to define
a Sort.

Note that – by default, rollback happens for runtime, unchecked exceptions


only. The checked exception does not trigger a rollback of the transaction; the
behavior can, of course, be configured with the rollbackFor and noRollbackFor
annotation parameters

https://www.baeldung.com/spring-data-jpa-query

https://www.baeldung.com/spring-scheduling-annotations

When single-threaded execution isn’t enough, we can use annotations from the
org.springframework.scheduling.annotation package.

Spring bean scopes

singleton
default
@Bean
@Scope("singleton")
prototype
A bean with prototype scope will return a different instance every time it is
requested from the

As mentioned, there are four additional scopes that are only available in a
web-aware application context
request
session
application
websocket

The request scope creates a bean instance for a single HTTP request while session
scope creates for an HTTP Session.

The application scope creates the bean instance for the lifecycle a ServletContext
and the websocket scope creates it for a particular WebSocket session.

byte b = 10;

// Using b = b+1
b = b + 1;
System.out.println(b);
/* Using typecasting will work
b=(byte)b+1;
System.out.println(b);*/

Threads can be created by using two mechanisms :


1. Extending the Thread class
2. Implementing the Runnable Interface

// Java code for thread creation by extending


// the Thread class
class MultithreadingDemo extends Thread
{
public void run()
{
try
{
// Displaying the thread that is running
System.out.println ("Thread " +
Thread.currentThread().getId() +
" is running");

}
catch (Exception e)
{
// Throwing an exception
System.out.println ("Exception is caught");
}
}
}

// Main Class
public class Multithread
{
public static void main(String[] args)
{
int n = 8; // Number of threads
for (int i=0; i<8; i++)
{
MultithreadingDemo object = new MultithreadingDemo();
object.start();
}
}
}

// Java code for thread creation by implementing


// the Runnable Interface
class MultithreadingDemo implements Runnable
{
public void run()
{
try
{
// Displaying the thread that is running
System.out.println ("Thread " +
Thread.currentThread().getId() +
" is running");

}
catch (Exception e)
{
// Throwing an exception
System.out.println ("Exception is caught");
}
}
}

// Main Class
class Multithread
{
public static void main(String[] args)
{
int n = 8; // Number of threads
for (int i=0; i<8; i++)
{
Thread object = new Thread(new MultithreadingDemo());
object.start();
}
}
}

https://www.geeksforgeeks.org/multithreading-in-java/

How can an object be unreferenced


1) By nulling a reference:
Employee e=new Employee();
e=null;

2) By assigning a reference to another:


Employee e1=new Employee();
Employee e2=new Employee();
e1=e2;//now the first object referred by e1 is available for garbage collection

3) By anonymous object:
new Employee();

Note: The Garbage collector of JVM collects only those objects that are
created by new keyword. So if you have created any object without new, you can use
finalize method to perform cleanup processing (destroying remaining objects).

Note: Garbage collection is performed by a daemon thread called Garbage


Collector(GC). This thread calls the finalize() method before object is garbage
collected.
Java Runtime class

Java Runtime class is used to interact with java runtime environment. Java Runtime
class provides methods to execute a process, invoke GC, get total and free memory
etc. There is only one instance of java.lang.Runtime class is available for one
java application.

The Runtime.getRuntime() method returns the singleton instance of Runtime class.

Synchronization in java is the capability to control the access of multiple threads


to any shared resource

####################################################

try with resource : added in java 7:


- can be used instead of finally block
- close resouce even if error have occurde

multiple exceptions in catch block


try {
//.....
} catch ( IllegalArgumentException | SecurityException |
IllegalAccessException |NoSuchFieldException exc) {

java 8
- interface can have static & default method implementations
- in case, where class implements 2 interface with same name, the class must
provide its own implementations

@NonfunctionalInterface
for interface having only one abstract method , similar to @Override anotations

LeadRepository -> JpaRepository -> PagingAndSortingRepository -> CrudRepository


-> Repository

@NonNullApi: Used on the package level to declare that the default behavior for
parameters and return values is to not accept or produce null values.

@org.springframework.lang.NonNullApi
package com.acme;

@NonNull: Used on a parameter or return value that must not be null (not needed on
a parameter and return value where @NonNullApi applies).

@Nullable: Used on a parameter or return value that can be null.

User getByEmailAddress(EmailAddress emailAddress);


Throws an EmptyResultDataAccessException when the query executed does
not produce a result. Throws an IllegalArgumentException when the emailAddress
handed to the method is null.

@Nullable
User findByEmailAddress(@Nullable EmailAddress emailAdress);

Returns null when the query executed does not produce a result. Also
accepts null as the value for emailAddress

Optional<User> findOptionalByEmailAddress(EmailAddress emailAddress);

Returns Optional.empty() when the query executed does not produce a


result. Throws an IllegalArgumentException when the emailAddress handed to the
method is null.

List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String


lastname);

// Enables the distinct flag for the query


List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String
firstname);
List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String
firstname);

// Enabling ignoring case for an individual property


List<Person> findByLastnameIgnoreCase(String lastname);
// Enabling ignoring case for all suitable properties
List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String
firstname);

// Enabling static ORDER BY for a query


List<Person> findByLastnameOrderByFirstnameAsc(String lastname);
List<Person> findByLastnameOrderByFirstnameDesc(String lastname);

User findFirstByOrderByLastnameAsc();

User findTopByOrderByAgeDesc();

Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);

Slice<User> findTop3ByLastname(String lastname, Pageable pageable);

List<User> findFirst10ByLastname(String lastname, Sort sort);


List<User> findTop10ByLastname(String lastname, Pageable pageable);

Named Queries

@Entity
@NamedQuery(name = "User.findByEmailAddress",
query = "select u from User u where u.emailAddress = ?1")
public class User {

public interface UserRepository extends JpaRepository<User, Long> {

@Query("select u from User u where u.emailAddress = ?1")


User findByEmailAddress(String emailAddress);
}

Nativ query
public interface UserRepository extends JpaRepository<User, Long> {

@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery


= true)
User findByEmailAddress(String emailAddress);
}

public interface UserRepository extends JpaRepository<User, Long> {

@Query("select u from User u where u.lastname like ?1%")


List<User> findByAndSort(String lastname, Sort sort);

@Query("select u.id, LENGTH(u.firstname) as fn_len from User u where u.lastname


like ?1%")
List<Object[]> findByAsArrayAndSort(String lastname, Sort sort);
}

repo.findByAndSort("lannister", new Sort("firstname"));


repo.findByAndSort("stark", new Sort("LENGTH(firstname)"));
repo.findByAndSort("targaryen", JpaSort.unsafe("LENGTH(firstname)"));
repo.findByAsArrayAndSort("bolton", new Sort("fn_len"));

named parameter

public interface UserRepository extends JpaRepository<User, Long> {

@Query("select u from User u where u.firstname = :firstname or u.lastname =


:lastname")
User findByLastnameOrFirstname(@Param("lastname") String lastname,
@Param("firstname") String firstname);
}

https://codepumpkin.com/hashset-internal-implementation/
========================================

Spring Annotations
==
org.springframework.context.annotation
public @interface Bean

Indicates that a method produces a bean to be managed by the Spring


container.

@Bean
public MyBean myBean() {
// instantiate and configure MyBean obj
return obj;
}

@Bean({"b1", "b2"}) // bean available as 'b1' and 'b2', but not 'myBean'
public MyBean myBean() {
// instantiate and configure MyBean obj
return obj;
}
Profile, Scope, Lazy, DependsOn, Primary, Order

Note that the @Bean annotation does not provide attributes for profile,
scope, lazy, depends-on or primary. Rather, it should be used in conjunction with
@Scope, @Lazy, @DependsOn and @Primary annotations to declare those semantics. For
example:

@Bean
@Profile("production")
@Scope("prototype")
public MyBean myBean() {
// instantiate and configure MyBean obj
return obj;
}

The semantics of the above-mentioned annotations match their use at the


component class level: @Profile allows for selective inclusion of certain beans.
@Scope changes the bean's scope from singleton to the specified scope.

@Lazy only has an actual effect in case of the default singleton scope.

@DependsOn enforces the creation of specific other beans before this bean
will be created, in addition to any dependencies that the bean expressed through
direct references, which is typically helpful for singleton startup.
@Primary is a mechanism to resolve ambiguity at the injection point level if
a single target component needs to be injected but several beans match by type.

Additionally, @Bean methods may also declare qualifier annotations and @Order
values, to be taken into account during injection point resolution just like
corresponding annotations on the corresponding component classes but potentially
being very individual per bean definition (in case of multiple definitions with the
same bean class). Qualifiers narrow the set of candidates after the initial type
match; order values determine the order of resolved elements in case of collection
injection points (with several target beans matching by type and qualifier).

NOTE: @Order values may influence priorities at injection points, but please
be aware that they do not influence singleton startup order which is an orthogonal
concern determined by dependency relationships and @DependsOn declarations as
mentioned above. Also, Priority is not available at this level since it cannot be
declared on methods; its semantics can be modeled through @Order values in
combination with @Primary on a single bean per type.

@Bean is generally used under classed marked with @Configuration


@Configuration classes and their factory methods must not be marked as final
or private in this mode.

@Bean methods may also be declared within classes that are not annotated with
@Configuration. For example, bean methods may be declared in a @Component class or
even in a plain old class. In such cases, a @Bean method will get processed in a
so-called 'lite' mode.
, 'inter-bean references' are not supported in lite mode. Instead, when one
@Bean-method invokes another @Bean-method in lite mode, the invocation is a
standard Java method invocation; Spring does not intercept the invocation via a
CGLIB proxy. This is analogous to inter-@Transactional method calls where in proxy
mode, Spring does not intercept the invocation — Spring does so only in AspectJ
mode.

BeanFactoryPostProcessor-returning @Bean methods


Special consideration must be taken for @Bean methods that return Spring
BeanFactoryPostProcessor (BFPP) types. Because BFPP objects must be instantiated
very early in the container lifecycle, they can interfere with processing of
annotations such as @Autowired, @Value, and @PostConstruct within @Configuration
classes. To avoid these lifecycle issues, mark BFPP-returning @Bean methods as
static. For example

marking this method as static, it can be invoked without causing


instantiation of its declaring @Configuration class, thus avoiding the above-
mentioned lifecycle conflicts. Note however that static @Bean methods will not be
enhanced for scoping and AOP semantics as mentioned above. This works out in BFPP
cases, as they are not typically referenced by other @Bean methods. As a reminder,
a WARN-level log message will be issued for any non-static @Bean methods having a
return type assignable to BeanFactoryPostProcessor.

Constraints when authoring @Configuration classes


Configuration classes must be provided as classes (i.e. not as
instances returned from factory methods), allowing for runtime enhancements through
a generated subclass.
Configuration classes must be non-final.
Configuration classes must be non-local (i.e. may not be declared
within a method).
Any nested configuration classes must be declared as static.
@Bean methods may not in turn create further configuration classes (any
such instances will be treated as regular beans, with their configuration
annotations remaining undetected).

==
@Override Why?
Use it every time you override a method for two benefits. Do it so that you can
take advantage of the compiler checking to make sure you actually are overriding a
method when you think you are. This way, if you make a common mistake of
misspelling a method name or not correctly matching the parameters, you will be
warned that you method does not actually override as you think it does. Secondly,
it makes your code easier to understand because it is more obvious when methods are
overwritten.

==

DecimalFormat df = new DecimalFormat("#.#####");


df.format(0.912385);
However as you can see this uses half-even rounding. That is it will round down if
the previous digit is even.

DecimalFormat df = new DecimalFormat("#.####");


df.setRoundingMode(RoundingMode.CEILING);

default Decimal mode uses RoundingMode.HALF_EVEN

==
Array list internally uses array
The default initial capacity of an ArrayList is pretty small (10 from Java 1.4 -
1.8). But since the underlying implementation is an array, the array must be
resized if you add a lot of elements. To avoid the high cost of resizing when you
know you're going to add a lot of elements, construct the ArrayList with a higher
initial capacity.

==

transient is a Java keyword which marks a member variable not to be serialized when
it is persisted to streams of bytes
@DoNotSerialize

==

Hasset internally uses hasmap, and puts values as keys of hasmap. so doen't allow
duplicate values. And for Value field it does set dummy value object with "PRESENT"
value

==

Generally Arralylist is prefered over linked list because it uses more memory to
store 2 additional addresses,

==

jps - the Java Process Status Application The tool is limited to reporting
information on JVMs for which it has the access permissions.

==
jstat -gc -h5 -t 14984 2500 30
jstat -gcutil 21891 250 7

jstat -gcnew -h3 21891 250

3 types of annotations

- marker
just mark, do not accept any value @Override
- single value
single member and it is mandatory
- full

Four are imported from java.lang.annotation: @Retention, @Documented, @Target, and


@Inherited.
Three are included in java.lang: @Deprecated, @Override and @SuppressWarnings

Starting with J2SE 5.0, you deprecate a class, method, or field by using the
@Deprecated annotation. Additionally, you can use the @deprecated Javadoc tag tell
developers what to use instead.

Using the @Deprecated annotation to deprecate a class, method, or field ensures


that all compilers will issue warnings when code uses that program element. In
contrast, there is no guarantee that all compilers will always issue warnings based
on the @deprecated Javadoc tag, though the Sun compilers currently do so. Other
compilers may not issue such warnings. Thus, using the @Deprecated annotation to
generate warnings is more portable that relying on the @deprecated Javadoc tag.

You can use the @deprecated tag to make Javadoc show a program element as
deprecated. The @deprecated tag must be followed by a space or newline. In the
paragraph following the @deprecated tag, explain why the item has been deprecated
and suggest what to use instead.

/**
* Delete multiple items from the list.
*
* @deprecated Not for public use.
* This method is expected to be retained only as a package
* private method. Replaced by
* {@link #remove(int)} and {@link #removeAll()}
*/
@Deprecated public synchronized void delItems(int start, int end) {
...
}

spring MVC

ApplicationContext instances in Spring can be scoped. In the Web MVC framework,


each DispatcherServlet has its own WebApplicationContext, which inherits all

@RequestMapping("/spring-web/{symbolicName:[a-z-]}-{version:\\d\\.\\d\\.\\d}
{extension:\\.[a-z]}")
public void handle(@PathVariable String version, @PathVariable String
extension) {
// ...
}
}

// GET /pets/42;q=11;r=22

@RequestMapping(value = "/pets/{petId}", method = RequestMethod.GET)


public void findPet(@PathVariable String petId, @MatrixVariable int q) {

// petId == 42
// q == 11

You might also like