├── .gitignore
├── LICENSE.txt
├── README.md
├── glassfish
├── README.md
├── pom.xml
└── src
│ ├── main
│ ├── java
│ │ └── com
│ │ │ └── samaxes
│ │ │ └── javax
│ │ │ └── rs
│ │ │ └── validation
│ │ │ ├── AcceptLanguageRequestFilter.java
│ │ │ ├── ApplicationConfig.java
│ │ │ ├── LocaleSpecificMessageInterpolator.java
│ │ │ ├── LocaleThreadLocal.java
│ │ │ ├── Person.java
│ │ │ ├── Persons.java
│ │ │ ├── ValidationConfigurationContextResolver.java
│ │ │ └── ValidationExceptionMapper.java
│ ├── resources
│ │ ├── ValidationMessages.properties
│ │ └── ValidationMessages_pt.properties
│ └── webapp
│ │ ├── WEB-INF
│ │ └── beans.xml
│ │ └── index.jsp
│ └── test
│ └── java
│ └── com
│ └── samaxes
│ └── javax
│ └── rs
│ └── validation
│ └── PersonsIT.java
└── wildfly
├── README.md
├── pom.xml
└── src
├── main
├── java
│ └── com
│ │ └── samaxes
│ │ └── javax
│ │ └── rs
│ │ └── validation
│ │ ├── AcceptLanguageRequestFilter.java
│ │ ├── ApplicationConfig.java
│ │ ├── LocaleSpecificMessageInterpolator.java
│ │ ├── LocaleThreadLocal.java
│ │ ├── Person.java
│ │ ├── Persons.java
│ │ ├── ValidationConfigurationContextResolver.java
│ │ └── ValidationExceptionMapper.java
├── resources
│ ├── ValidationMessages.properties
│ └── ValidationMessages_pt.properties
└── webapp
│ ├── WEB-INF
│ └── beans.xml
│ └── index.jsp
└── test
└── java
└── com
└── samaxes
└── javax
└── rs
└── validation
└── PersonsIT.java
/.gitignore:
--------------------------------------------------------------------------------
1 | glassfish/target
2 | glassfish/.settings
3 | glassfish/.project
4 | glassfish/.classpath
5 | glassfish/.idea
6 | glassfish/glassfish-jaxrs-validation.iml
7 | wildfly/target
8 | wildfly/.settings
9 | wildfly/.project
10 | wildfly/.classpath
11 | wildfly/.idea
12 | wildfly/wildfly-jaxrs-validation.iml
13 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Validating JAX-RS resource data with Bean Validation in Java EE 7
2 |
3 | This project goal is to demonstrate that, despite the used technologies being part of the Java EE 7 specification, proprietary dependencies are required to properly internationalize the error messages produced by Bean Validation.
4 |
5 | * The Glassfish code was first used on an article written for [JAX Magazine](http://jaxenter.com/jax-magazine/JAX-Magazine-2013-06) and later posted on [JAXenter](http://jaxenter.com/integrating-bean-validation-with-jax-rs-48461.html).
6 | * The WildFly code was used for a post on my own blog at [Validating JAX-RS resource data with Bean Validation in Java EE 7 and WildFly](http://www.samaxes.com/2014/04/jaxrs-beanvalidation-javaee7-wildfly/).
7 |
--------------------------------------------------------------------------------
/glassfish/README.md:
--------------------------------------------------------------------------------
1 | # Integrating JAX-RS with Bean Validation and internationalize error messages in GlassFish 4
2 |
3 | * This code was first used on an article written for [JAX Magazine](http://jaxenter.com/jax-magazine/JAX-Magazine-2013-06) and later posted on [JAXenter](http://jaxenter.com/integrating-bean-validation-with-jax-rs-48461.html).
4 |
--------------------------------------------------------------------------------
/glassfish/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.samaxes.javaee7
7 | glassfish-jaxrs-validation
8 | 0.0.1-SNAPSHOT
9 | war
10 |
11 | Validating JAX-RS resource data with Bean Validation in Java EE 7
12 | Integrating JAX-RS with Bean Validation and internationalize error messages in GlassFish
13 | https://github.com/samaxes/jaxrs-beanvalidation-javaee7
14 | 2013
15 |
16 | samaxes
17 | http://www.samaxes.com/
18 |
19 |
20 |
21 | The Apache Software License, Version 2.0
22 | http://www.apache.org/licenses/LICENSE-2.0.txt
23 | repo
24 |
25 |
26 |
27 |
28 |
29 | samaxes
30 | Samuel Santos
31 | http://www.samaxes.com/
32 |
33 | project owner
34 | developer
35 |
36 | 0
37 |
38 |
39 |
40 |
41 | GitHub
42 | https://github.com/samaxes/jaxrs-beanvalidation-javaee7/issues
43 |
44 |
45 | scm:git:git://github.com/samaxes/jaxrs-beanvalidation-javaee7.git
46 | scm:git:git@github.com:samaxes/jaxrs-beanvalidation-javaee7.git
47 | https://github.com/samaxes/jaxrs-beanvalidation-javaee7
48 |
49 |
50 |
51 | 3.0
52 |
53 |
54 |
55 | jaxrs-beanvalidation-javaee7
56 |
57 |
58 | org.apache.maven.plugins
59 | maven-compiler-plugin
60 | 3.1
61 |
62 | ${maven.compiler.source}
63 | ${maven.compiler.target}
64 | ${project.build.sourceEncoding}
65 |
66 |
67 |
68 | org.apache.maven.plugins
69 | maven-resources-plugin
70 | 2.6
71 |
72 | ${project.build.resourceEncoding}
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-war-plugin
78 | 2.4
79 |
80 |
81 |
82 | true
83 |
84 |
85 | false
86 |
87 |
88 |
89 | org.apache.maven.plugins
90 | maven-surefire-plugin
91 | ${surefire.version}
92 |
93 | true
94 |
95 |
96 |
97 | org.apache.maven.plugins
98 | maven-failsafe-plugin
99 | ${surefire.version}
100 |
101 | ${project.build.sourceEncoding}
102 |
103 |
104 |
105 | integration-test
106 |
107 | integration-test
108 |
109 |
110 |
111 | verify
112 |
113 | verify
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 | org.jboss.arquillian
125 | arquillian-bom
126 | 1.1.3.Final
127 | import
128 | pom
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | org.jboss.arquillian.junit
137 | arquillian-junit-container
138 | test
139 |
140 |
141 | org.jboss.shrinkwrap.resolver
142 | shrinkwrap-resolver-depchain
143 | test
144 | pom
145 |
146 |
147 | org.jboss.arquillian.container
148 | arquillian-glassfish-embedded-3.1
149 | 1.0.0.CR4
150 | test
151 |
152 |
153 | junit
154 | junit
155 | 4.11
156 | test
157 |
158 |
159 |
160 | javax
161 | javaee-api
162 | 7.0
163 | provided
164 |
165 |
166 | org.glassfish.main.extras
167 | glassfish-embedded-all
168 | 4.0
169 | provided
170 |
171 |
172 |
173 |
174 |
175 | UTF-8
176 | ISO-8859-1
177 | 1.7
178 | 1.7
179 | 2.16
180 |
181 |
182 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/AcceptLanguageRequestFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.io.IOException;
22 |
23 | import javax.ws.rs.container.ContainerRequestContext;
24 | import javax.ws.rs.container.ContainerRequestFilter;
25 | import javax.ws.rs.ext.Provider;
26 |
27 | /**
28 | * Checks whether the {@code Accept-Language} HTTP header exists and creates a {@link ThreadLocal} to store the
29 | * corresponding Locale.
30 | */
31 | @Provider
32 | public class AcceptLanguageRequestFilter implements ContainerRequestFilter {
33 |
34 | /*
35 | * (non-Javadoc)
36 | * @see javax.ws.rs.container.ContainerRequestFilter#filter(javax.ws.rs.container.ContainerRequestContext)
37 | */
38 | @Override
39 | public void filter(ContainerRequestContext requestContext) throws IOException {
40 | if (!requestContext.getAcceptableLanguages().isEmpty()) {
41 | LocaleThreadLocal.set(requestContext.getAcceptableLanguages().get(0));
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/ApplicationConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import javax.ws.rs.ApplicationPath;
22 | import javax.ws.rs.core.Application;
23 |
24 | @ApplicationPath("r")
25 | public class ApplicationConfig extends Application {
26 | }
27 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/LocaleSpecificMessageInterpolator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.Locale;
22 | import java.util.logging.Level;
23 | import java.util.logging.Logger;
24 |
25 | import javax.validation.MessageInterpolator;
26 |
27 | /**
28 | * Delegates to a MessageInterpolator implementation but enforces a given Locale.
29 | */
30 | public class LocaleSpecificMessageInterpolator implements MessageInterpolator {
31 |
32 | private static final Logger LOGGER = Logger.getLogger(LocaleSpecificMessageInterpolator.class.getName());
33 |
34 | private final MessageInterpolator defaultInterpolator;
35 |
36 | public LocaleSpecificMessageInterpolator(MessageInterpolator interpolator) {
37 | this.defaultInterpolator = interpolator;
38 | }
39 |
40 | /**
41 | * Enforces the locale passed to the interpolator.
42 | */
43 | @Override
44 | public String interpolate(String message, Context context) {
45 | LOGGER.log(Level.CONFIG, "Selecting the language " + LocaleThreadLocal.get() + " for the error message.");
46 | return defaultInterpolator.interpolate(message, context, LocaleThreadLocal.get());
47 | }
48 |
49 | /*
50 | * (non-Javadoc)
51 | * @see javax.validation.MessageInterpolator#interpolate(java.lang.String,
52 | * javax.validation.MessageInterpolator.Context, java.util.Locale)
53 | */
54 | @Override
55 | public String interpolate(String message, Context context, Locale locale) {
56 | return defaultInterpolator.interpolate(message, context, locale);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/LocaleThreadLocal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.Locale;
22 |
23 | /**
24 | * {@link ThreadLocal} to store the Locale to be used in the message interpolator.
25 | */
26 | public class LocaleThreadLocal {
27 |
28 | public static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
29 |
30 | public static Locale get() {
31 | return (THREAD_LOCAL.get() == null) ? Locale.getDefault() : THREAD_LOCAL.get();
32 | }
33 |
34 | public static void set(Locale locale) {
35 | THREAD_LOCAL.set(locale);
36 | }
37 |
38 | public static void unset() {
39 | THREAD_LOCAL.remove();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/Person.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import javax.validation.constraints.NotNull;
22 | import javax.validation.constraints.Size;
23 | import javax.xml.bind.annotation.XmlAccessType;
24 | import javax.xml.bind.annotation.XmlAccessorType;
25 | import javax.xml.bind.annotation.XmlRootElement;
26 |
27 | @XmlRootElement
28 | @XmlAccessorType(XmlAccessType.FIELD)
29 | public class Person {
30 |
31 | @NotNull
32 | private Integer id;
33 |
34 | @NotNull
35 | @Size(min = 2, max = 50)
36 | private String name;
37 |
38 | public Integer getId() { return id; }
39 | public void setId(Integer id) { this.id = id; }
40 | public String getName() { return name; }
41 | public void setName(String name) { this.name = name; }
42 |
43 | @Override
44 | public int hashCode() {
45 | final int prime = 31;
46 | int result = 1;
47 | result = prime * result + ((id == null) ? 0 : id.hashCode());
48 | result = prime * result + ((name == null) ? 0 : name.hashCode());
49 | return result;
50 | }
51 |
52 | @Override
53 | public boolean equals(Object obj) {
54 | if (this == obj) {
55 | return true;
56 | }
57 | if (obj == null) {
58 | return false;
59 | }
60 | if (getClass() != obj.getClass()) {
61 | return false;
62 | }
63 | Person other = (Person) obj;
64 | if (id == null) {
65 | if (other.id != null) {
66 | return false;
67 | }
68 | } else if (!id.equals(other.id)) {
69 | return false;
70 | }
71 | if (name == null) {
72 | if (other.name != null) {
73 | return false;
74 | }
75 | } else if (!name.equals(other.name)) {
76 | return false;
77 | }
78 | return true;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/Persons.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.Collection;
22 | import java.util.concurrent.ConcurrentHashMap;
23 | import java.util.concurrent.ConcurrentMap;
24 |
25 | import javax.validation.constraints.NotNull;
26 | import javax.validation.constraints.Pattern;
27 | import javax.validation.constraints.Size;
28 | import javax.ws.rs.Consumes;
29 | import javax.ws.rs.FormParam;
30 | import javax.ws.rs.GET;
31 | import javax.ws.rs.POST;
32 | import javax.ws.rs.Path;
33 | import javax.ws.rs.PathParam;
34 | import javax.ws.rs.Produces;
35 | import javax.ws.rs.core.MediaType;
36 | import javax.ws.rs.core.Response;
37 |
38 | @Path("persons")
39 | @Produces(MediaType.APPLICATION_JSON)
40 | public class Persons {
41 |
42 | private static final ConcurrentMap persons = new ConcurrentHashMap();
43 |
44 | @GET
45 | public Collection getAll() {
46 | return persons.values();
47 | }
48 |
49 | @GET
50 | @Path("{id}")
51 | public Person getPerson(
52 | @PathParam("id")
53 | @NotNull(message = "The id must not be null")
54 | @Pattern(regexp = "[0-9]+", message = "The id must be a valid number")
55 | String id) {
56 | return persons.get(id);
57 | }
58 |
59 | @POST
60 | @Path("create")
61 | @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
62 | public Response createPerson(
63 | @FormParam("id")
64 | @NotNull(message = "{person.id.notnull}")
65 | @Pattern(regexp = "[0-9]+", message = "{person.id.pattern}")
66 | String id,
67 | @FormParam("name")
68 | @Size(min = 2, max = 50, message = "{person.name.size}")
69 | String name) {
70 | Person person = new Person();
71 | person.setId(Integer.valueOf(id));
72 | person.setName(name);
73 | persons.put(id, person);
74 | return Response.status(Response.Status.CREATED).entity(person).build();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/ValidationConfigurationContextResolver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.lang.reflect.Constructor;
22 | import java.lang.reflect.Method;
23 | import java.util.Arrays;
24 | import java.util.List;
25 |
26 | import javax.validation.ParameterNameProvider;
27 | import javax.validation.Validation;
28 | import javax.ws.rs.ext.ContextResolver;
29 | import javax.ws.rs.ext.Provider;
30 |
31 | import org.glassfish.jersey.server.validation.ValidationConfig;
32 |
33 | /**
34 | * Custom configuration of validation. This configuration can define custom:
35 | *
36 | *
MessageInterpolator - interpolates a given constraint violation message.
37 | *
TraversableResolver - determines if a property can be accessed by the Bean Validation provider.
38 | *
ConstraintValidatorFactory - instantiates a ConstraintValidator instance based off its class.
39 | *
ParameterNameProvider - provides names for method and constructor parameters.
*
40 | *
41 | */
42 | @Provider
43 | public class ValidationConfigurationContextResolver implements ContextResolver {
44 |
45 | /**
46 | * Get a context of type {@code ValidationConfig} that is applicable to the supplied type.
47 | *
48 | * @param type the class of object for which a context is desired
49 | * @return a context for the supplied type or {@code null} if a context for the supplied type is not available from
50 | * this provider.
51 | */
52 | @Override
53 | public ValidationConfig getContext(Class> type) {
54 | final ValidationConfig config = new ValidationConfig();
55 |
56 | config.setMessageInterpolator(new LocaleSpecificMessageInterpolator(Validation.byDefaultProvider().configure()
57 | .getDefaultMessageInterpolator()));
58 | config.setParameterNameProvider(new CustomParameterNameProvider());
59 |
60 | return config;
61 | }
62 |
63 | /**
64 | * If method input parameters are invalid, this class returns actual parameter names instead of the default ones (
65 | * {@code arg0, arg1, ...})
66 | */
67 | private class CustomParameterNameProvider implements ParameterNameProvider {
68 |
69 | private final ParameterNameProvider nameProvider;
70 |
71 | public CustomParameterNameProvider() {
72 | nameProvider = Validation.byDefaultProvider().configure().getDefaultParameterNameProvider();
73 | }
74 |
75 | @Override
76 | public List getParameterNames(final Constructor> constructor) {
77 | return nameProvider.getParameterNames(constructor);
78 | }
79 |
80 | @Override
81 | public List getParameterNames(final Method method) {
82 | if ("getPerson".equals(method.getName())) {
83 | return Arrays.asList("id");
84 | }
85 | if ("createPerson".equals(method.getName())) {
86 | return Arrays.asList("id", "name");
87 | }
88 | return nameProvider.getParameterNames(method);
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/glassfish/src/main/java/com/samaxes/javax/rs/validation/ValidationExceptionMapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.ArrayList;
22 | import java.util.Arrays;
23 | import java.util.Iterator;
24 | import java.util.List;
25 | import java.util.Set;
26 | import java.util.logging.Level;
27 | import java.util.logging.Logger;
28 |
29 | import javax.inject.Provider;
30 | import javax.validation.ConstraintViolation;
31 | import javax.validation.ConstraintViolationException;
32 | import javax.validation.ElementKind;
33 | import javax.validation.Path;
34 | import javax.validation.ValidationException;
35 | import javax.ws.rs.core.Configuration;
36 | import javax.ws.rs.core.Context;
37 | import javax.ws.rs.core.GenericEntity;
38 | import javax.ws.rs.core.GenericType;
39 | import javax.ws.rs.core.MediaType;
40 | import javax.ws.rs.core.Request;
41 | import javax.ws.rs.core.Response;
42 | import javax.ws.rs.core.Variant;
43 | import javax.ws.rs.ext.ExceptionMapper;
44 |
45 | import org.glassfish.jersey.server.validation.ValidationError;
46 | import org.glassfish.jersey.server.validation.internal.LocalizationMessages;
47 |
48 | /**
49 | * {@link ExceptionMapper} for {@link ValidationException}.
50 | *
51 | * Send a list of {@link ValidationError} instances in {@link Response} in addition to HTTP 400/500 status code.
52 | * Supported media types are: {@code application/json} / {@code application/xml} (if appropriate provider is registered
53 | * on server).
54 | *
55 | *
56 | * @see org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper The original Glassfish class:
57 | * {@code org.glassfish.jersey.server.validation.internal.ValidationExceptionMapper}
58 | */
59 | @javax.ws.rs.ext.Provider
60 | public class ValidationExceptionMapper implements ExceptionMapper {
61 |
62 | private static final Logger LOGGER = Logger.getLogger(ValidationExceptionMapper.class.getName());
63 |
64 | @Context
65 | private Configuration config;
66 |
67 | @Context
68 | private Provider request;
69 |
70 | @Override
71 | public Response toResponse(final ValidationException exception) {
72 | if (exception instanceof ConstraintViolationException) {
73 | LOGGER.log(Level.FINER, LocalizationMessages.CONSTRAINT_VIOLATIONS_ENCOUNTERED(), exception);
74 |
75 | final ConstraintViolationException cve = (ConstraintViolationException) exception;
76 | final Response.ResponseBuilder response = Response.status(getStatus(cve));
77 |
78 | // Entity
79 | final List variants = Variant.mediaTypes(
80 | MediaType.APPLICATION_XML_TYPE,
81 | MediaType.APPLICATION_JSON_TYPE).build();
82 | final Variant variant = request.get().selectVariant(variants);
83 | if (variant != null) {
84 | response.type(variant.getMediaType());
85 | } else {
86 | /*
87 | * default media type which will be used only when none media type from {@value variants} is in
88 | * accept header of original request.
89 | */
90 | response.type(MediaType.TEXT_PLAIN_TYPE);
91 | }
92 | response.entity(
93 | new GenericEntity>(
94 | getEntity(cve.getConstraintViolations()),
95 | new GenericType>() {}.getType()
96 | )
97 | );
98 |
99 | return response.build();
100 | } else {
101 | LOGGER.log(Level.WARNING, LocalizationMessages.VALIDATION_EXCEPTION_RAISED(), exception);
102 |
103 | return Response.serverError().entity(exception.getMessage()).build();
104 | }
105 | }
106 |
107 | private List getEntity(final Set> violations) {
108 | final List errors = new ArrayList();
109 |
110 | for (final ConstraintViolation> violation : violations) {
111 | errors.add(new ValidationError(violation.getMessage(), violation.getMessageTemplate(), getPath(violation),
112 | getInvalidValue(violation.getInvalidValue())));
113 | }
114 |
115 | return errors;
116 | }
117 |
118 | private String getInvalidValue(final Object invalidValue) {
119 | if (invalidValue == null) {
120 | return null;
121 | }
122 |
123 | if (invalidValue.getClass().isArray()) {
124 | return Arrays.toString((Object[]) invalidValue);
125 | }
126 |
127 | return invalidValue.toString();
128 | }
129 |
130 | private Response.Status getStatus(final ConstraintViolationException exception) {
131 | return getResponseStatus(exception.getConstraintViolations());
132 | }
133 |
134 | private Response.Status getResponseStatus(final Set> constraintViolations) {
135 | final Iterator> iterator = constraintViolations.iterator();
136 |
137 | if (iterator.hasNext()) {
138 | return getResponseStatus(iterator.next());
139 | } else {
140 | return Response.Status.BAD_REQUEST;
141 | }
142 | }
143 |
144 | private Response.Status getResponseStatus(final ConstraintViolation> constraintViolation) {
145 | for (final Path.Node node : constraintViolation.getPropertyPath()) {
146 | final ElementKind kind = node.getKind();
147 |
148 | if (ElementKind.RETURN_VALUE.equals(kind)) {
149 | return Response.Status.INTERNAL_SERVER_ERROR;
150 | }
151 | }
152 |
153 | return Response.Status.BAD_REQUEST;
154 | }
155 |
156 | private String getPath(final ConstraintViolation> violation) {
157 | final String leafBeanName = violation.getLeafBean().getClass().getSimpleName();
158 | final String leafBeanCleanName = (leafBeanName.contains("$")) ? leafBeanName.substring(0,
159 | leafBeanName.indexOf("$")) : leafBeanName;
160 | final String propertyPath = violation.getPropertyPath().toString();
161 |
162 | return leafBeanCleanName + (!"".equals(propertyPath) ? '.' + propertyPath : "");
163 | }
164 | }
165 |
--------------------------------------------------------------------------------
/glassfish/src/main/resources/ValidationMessages.properties:
--------------------------------------------------------------------------------
1 | person.id.notnull=The person id must not be null
2 | person.id.pattern=The person id must be a valid number
3 | person.name.size=The person name must be between {min} and {max} chars long
4 |
--------------------------------------------------------------------------------
/glassfish/src/main/resources/ValidationMessages_pt.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samaxes/jaxrs-beanvalidation-javaee7/e801ce84f3686e9c5e03b1a8285e2ce5abbff56f/glassfish/src/main/resources/ValidationMessages_pt.properties
--------------------------------------------------------------------------------
/glassfish/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/glassfish/src/main/webapp/index.jsp:
--------------------------------------------------------------------------------
1 | <%@page contentType="text/html" pageEncoding="UTF-8" %>
2 |
3 |
4 |
5 |
6 | Validating JAX-RS resource data with Bean Validation in Java EE 7
7 |
8 |
15 |
16 |
17 |
18 |
Validating JAX-RS resource data with Bean Validation in Java EE 7
19 |
20 |
21 |
22 | Get all
23 |
24 |
25 |
29 |
30 |
31 |
36 |
37 |
38 |
41 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/glassfish/src/test/java/com/samaxes/javax/rs/validation/PersonsIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.io.IOException;
22 | import java.net.URL;
23 | import java.util.Collection;
24 | import java.util.Collections;
25 | import java.util.logging.Logger;
26 |
27 | import javax.json.JsonArray;
28 | import javax.json.JsonObject;
29 | import javax.json.JsonValue;
30 | import javax.json.stream.JsonGenerator;
31 | import javax.servlet.http.HttpServletResponse;
32 | import javax.ws.rs.client.Client;
33 | import javax.ws.rs.client.ClientBuilder;
34 | import javax.ws.rs.client.Entity;
35 | import javax.ws.rs.core.Form;
36 | import javax.ws.rs.core.GenericType;
37 | import javax.ws.rs.core.MediaType;
38 | import javax.ws.rs.core.Response;
39 |
40 | import org.glassfish.jersey.jsonp.JsonProcessingFeature;
41 | import org.jboss.arquillian.container.test.api.Deployment;
42 | import org.jboss.arquillian.container.test.api.RunAsClient;
43 | import org.jboss.arquillian.junit.Arquillian;
44 | import org.jboss.arquillian.junit.InSequence;
45 | import org.jboss.arquillian.test.api.ArquillianResource;
46 | import org.jboss.shrinkwrap.api.ArchivePaths;
47 | import org.jboss.shrinkwrap.api.ShrinkWrap;
48 | import org.jboss.shrinkwrap.api.asset.EmptyAsset;
49 | import org.jboss.shrinkwrap.api.formatter.Formatters;
50 | import org.jboss.shrinkwrap.api.spec.WebArchive;
51 | import org.junit.Assert;
52 | import org.junit.Test;
53 | import org.junit.runner.RunWith;
54 |
55 | @RunWith(Arquillian.class)
56 | public class PersonsIT {
57 |
58 | private static final Logger LOGGER = Logger.getLogger(PersonsIT.class.getName());
59 |
60 | @Deployment
61 | public static WebArchive createDeployment() throws IOException {
62 | final WebArchive war = ShrinkWrap.create(WebArchive.class, "jaxrs-beanvalidation-javaee7.war")
63 | .addPackage("com.samaxes.javax.rs.validation")
64 | .addAsWebInfResource(EmptyAsset.INSTANCE, ArchivePaths.create("beans.xml"));
65 |
66 | LOGGER.info(war.toString(Formatters.VERBOSE));
67 |
68 | return war;
69 | }
70 |
71 | @Test
72 | @RunAsClient
73 | @InSequence(10)
74 | public void shouldReturnAllPersons(@ArquillianResource URL baseURL) {
75 | Client client = ClientBuilder.newBuilder()
76 | .register(JsonProcessingFeature.class)
77 | .property(JsonGenerator.PRETTY_PRINTING, true)
78 | .build();
79 | Response response = client.target(baseURL + "r/persons")
80 | .request(MediaType.APPLICATION_JSON)
81 | .get();
82 | response.bufferEntity();
83 |
84 | logResponse("shouldReturnAllPersons", response, JsonArray.class);
85 | Assert.assertEquals(Collections.emptyList(), response.readEntity(new GenericType>() {}));
86 | }
87 |
88 | @Test
89 | @RunAsClient
90 | @InSequence(20)
91 | public void shouldReturnAValidationErrorWhenGettingAPerson(@ArquillianResource URL baseURL) {
92 | Client client = ClientBuilder.newBuilder()
93 | .register(JsonProcessingFeature.class)
94 | .property(JsonGenerator.PRETTY_PRINTING, true)
95 | .build();
96 | Response response = client.target(baseURL + "r/persons/{id}")
97 | .resolveTemplate("id", "test")
98 | .request(MediaType.APPLICATION_JSON)
99 | .header("Accept-Language", "en")
100 | .get();
101 | response.bufferEntity();
102 |
103 | logResponse("shouldReturnAValidationErrorWhenGettingAPerson", response, JsonObject.class);
104 | Assert.assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
105 | }
106 |
107 | @Test
108 | @RunAsClient
109 | @InSequence(30)
110 | public void shouldReturnAnEmptyPerson(@ArquillianResource URL baseURL) {
111 | Client client = ClientBuilder.newBuilder()
112 | .register(JsonProcessingFeature.class)
113 | .property(JsonGenerator.PRETTY_PRINTING, true)
114 | .build();
115 | Response response = client.target(baseURL + "r/persons/{id}")
116 | .resolveTemplate("id", "10")
117 | .request(MediaType.APPLICATION_JSON)
118 | .get();
119 | response.bufferEntity();
120 |
121 | logResponse("shouldReturnAnEmptyPerson", response, JsonObject.class);
122 | Assert.assertEquals(null, response.readEntity(Person.class));
123 | }
124 |
125 | @Test
126 | @RunAsClient
127 | @InSequence(40)
128 | public void shouldReturnAValidationErrorWhenCreatingAPerson(@ArquillianResource URL baseURL) {
129 | Form form = new Form();
130 |
131 | Client client = ClientBuilder.newBuilder()
132 | .register(JsonProcessingFeature.class)
133 | .property(JsonGenerator.PRETTY_PRINTING, true)
134 | .build();
135 | Response response = client.target(baseURL + "r/persons/create")
136 | .request(MediaType.APPLICATION_JSON)
137 | .header("Accept-Language", "pt")
138 | .post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED));
139 | response.bufferEntity();
140 |
141 | logResponse("shouldReturnAValidationErrorWhenCreatingAPerson", response, JsonObject.class);
142 | Assert.assertEquals(HttpServletResponse.SC_BAD_REQUEST, response.getStatus());
143 | }
144 |
145 | @Test
146 | @RunAsClient
147 | @InSequence(50)
148 | public void shouldReturnACreatedPerson(@ArquillianResource URL baseURL) {
149 | Person person = new Person();
150 | person.setId(20);
151 | person.setName("sam");
152 | Form form = new Form();
153 | form.param("id", String.valueOf(person.getId()));
154 | form.param("name", person.getName());
155 |
156 | Client client = ClientBuilder.newBuilder()
157 | .register(JsonProcessingFeature.class)
158 | .property(JsonGenerator.PRETTY_PRINTING, true)
159 | .build();
160 | Response response = client.target(baseURL + "r/persons/create")
161 | .request(MediaType.APPLICATION_JSON)
162 | .post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED));
163 | response.bufferEntity();
164 |
165 | logResponse("shouldReturnACreatedPerson", response, JsonObject.class);
166 | Assert.assertEquals(person, response.readEntity(Person.class));
167 | }
168 |
169 | private void logResponse(String method, Response response, Class extends JsonValue> type) {
170 | StringBuilder builder = new StringBuilder(method).append("\n");
171 | builder.append("Response: ").append(response).append("\n");
172 | builder.append("Entity: ");
173 | if (MediaType.APPLICATION_JSON_TYPE.equals(response.getMediaType())) {
174 | builder.append(response.readEntity(type));
175 | }
176 | builder.append("\n");
177 | LOGGER.info(builder.toString());
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/wildfly/README.md:
--------------------------------------------------------------------------------
1 | # Integrating JAX-RS with Bean Validation and internationalize error messages in WildFly 8
2 |
3 | * This code was used for a post on my own blog at [Validating JAX-RS resource data with Bean Validation in Java EE 7 and WildFly](http://www.samaxes.com/2014/04/jaxrs-beanvalidation-javaee7-wildfly/).
4 |
--------------------------------------------------------------------------------
/wildfly/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 |
6 | com.samaxes.javaee7
7 | wildfly-jaxrs-validation
8 | 0.0.1-SNAPSHOT
9 | war
10 |
11 | Validating JAX-RS resource data with Bean Validation in Java EE 7
12 | Integrating JAX-RS with Bean Validation and internationalize error messages in WildFly
13 | https://github.com/samaxes/jaxrs-beanvalidation-javaee7
14 | 2014
15 |
16 | samaxes
17 | http://www.samaxes.com/
18 |
19 |
20 |
21 | The Apache Software License, Version 2.0
22 | http://www.apache.org/licenses/LICENSE-2.0.txt
23 | repo
24 |
25 |
26 |
27 |
28 |
29 | samaxes
30 | Samuel Santos
31 | http://www.samaxes.com/
32 |
33 | project owner
34 | developer
35 |
36 | 0
37 |
38 |
39 |
40 |
41 | GitHub
42 | https://github.com/samaxes/jaxrs-beanvalidation-javaee7/issues
43 |
44 |
45 | scm:git:git://github.com/samaxes/jaxrs-beanvalidation-javaee7.git
46 | scm:git:git@github.com:samaxes/jaxrs-beanvalidation-javaee7.git
47 | https://github.com/samaxes/jaxrs-beanvalidation-javaee7
48 |
49 |
50 |
51 | 3.0
52 |
53 |
54 |
55 | jaxrs-beanvalidation-javaee7
56 |
57 |
58 | org.apache.maven.plugins
59 | maven-compiler-plugin
60 | 3.1
61 |
62 | ${maven.compiler.source}
63 | ${maven.compiler.target}
64 | ${project.build.sourceEncoding}
65 |
66 |
67 |
68 | org.apache.maven.plugins
69 | maven-resources-plugin
70 | 2.6
71 |
72 | ${project.build.resourceEncoding}
73 |
74 |
75 |
76 | org.apache.maven.plugins
77 | maven-war-plugin
78 | 2.4
79 |
80 |
81 |
82 | true
83 |
84 |
85 | false
86 |
87 |
88 |
89 | org.apache.maven.plugins
90 | maven-dependency-plugin
91 | 2.8
92 |
93 |
94 | unpack
95 | pre-integration-test
96 |
97 | unpack
98 |
99 |
100 |
101 |
102 | org.wildfly
103 | wildfly-dist
104 | ${wildfly.version}
105 | zip
106 | ${project.build.directory}
107 | false
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 | org.apache.maven.plugins
116 | maven-surefire-plugin
117 | ${surefire.version}
118 |
119 | true
120 |
121 |
122 |
123 | org.apache.maven.plugins
124 | maven-failsafe-plugin
125 | ${surefire.version}
126 |
127 | ${project.build.sourceEncoding}
128 |
129 | org.jboss.logmanager.LogManager
130 | ${wildfly.home}
131 | ${wildfly.home}/modules
132 |
133 |
134 |
135 |
136 | integration-test
137 |
138 | integration-test
139 |
140 |
141 |
142 | verify
143 |
144 | verify
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 | org.jboss.arquillian
156 | arquillian-bom
157 | 1.1.4.Final
158 | import
159 | pom
160 |
161 |
162 | org.jboss.resteasy
163 | resteasy-bom
164 | 3.0.6.Final
165 | import
166 | pom
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 | junit
175 | junit
176 | 4.11
177 | test
178 |
179 |
180 | org.jboss.arquillian.junit
181 | arquillian-junit-container
182 | test
183 |
184 |
185 | org.jboss.shrinkwrap.resolver
186 | shrinkwrap-resolver-depchain
187 | test
188 | pom
189 |
190 |
191 | org.wildfly
192 | wildfly-arquillian-container-embedded
193 | ${wildfly.version}
194 | test
195 |
196 |
197 |
201 | org.jboss.resteasy
202 | resteasy-client
203 | test
204 |
205 |
206 | org.jboss.resteasy
207 | resteasy-jackson2-provider
208 | test
209 |
210 |
211 |
212 | javax
213 | javaee-api
214 | 7.0
215 | provided
216 |
217 |
223 |
224 | org.jboss.resteasy
225 | resteasy-jaxrs
226 | provided
227 |
228 |
229 | org.jboss.resteasy
230 | resteasy-validator-provider-11
231 | provided
232 |
233 |
234 |
235 |
236 |
237 | UTF-8
238 | ISO-8859-1
239 | 1.7
240 | 1.7
241 | 2.17
242 | 8.0.0.Final
243 | ${project.build.directory}/wildfly-${wildfly.version}
244 |
245 |
246 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/AcceptLanguageRequestFilter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.io.IOException;
22 |
23 | import javax.ws.rs.container.ContainerRequestContext;
24 | import javax.ws.rs.container.ContainerRequestFilter;
25 | import javax.ws.rs.ext.Provider;
26 |
27 | /**
28 | * Checks whether the {@code Accept-Language} HTTP header exists and creates a {@link ThreadLocal} to store the
29 | * corresponding Locale.
30 | */
31 | @Provider
32 | public class AcceptLanguageRequestFilter implements ContainerRequestFilter {
33 |
34 | /*
35 | * (non-Javadoc)
36 | * @see javax.ws.rs.container.ContainerRequestFilter#filter(javax.ws.rs.container.ContainerRequestContext)
37 | */
38 | @Override
39 | public void filter(ContainerRequestContext requestContext) throws IOException {
40 | if (!requestContext.getAcceptableLanguages().isEmpty()) {
41 | LocaleThreadLocal.set(requestContext.getAcceptableLanguages().get(0));
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/ApplicationConfig.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import javax.ws.rs.ApplicationPath;
22 | import javax.ws.rs.core.Application;
23 |
24 | @ApplicationPath("r")
25 | public class ApplicationConfig extends Application {
26 | }
27 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/LocaleSpecificMessageInterpolator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.Locale;
22 | import java.util.logging.Level;
23 | import java.util.logging.Logger;
24 |
25 | import javax.validation.MessageInterpolator;
26 |
27 | /**
28 | * Delegates to a MessageInterpolator implementation but enforces a given Locale.
29 | */
30 | public class LocaleSpecificMessageInterpolator implements MessageInterpolator {
31 |
32 | private static final Logger LOGGER = Logger.getLogger(LocaleSpecificMessageInterpolator.class.getName());
33 |
34 | private final MessageInterpolator defaultInterpolator;
35 |
36 | public LocaleSpecificMessageInterpolator(MessageInterpolator interpolator) {
37 | this.defaultInterpolator = interpolator;
38 | }
39 |
40 | /**
41 | * Enforces the locale passed to the interpolator.
42 | */
43 | @Override
44 | public String interpolate(String message, Context context) {
45 | LOGGER.log(Level.CONFIG, "Selecting the language " + LocaleThreadLocal.get() + " for the error message.");
46 | return defaultInterpolator.interpolate(message, context, LocaleThreadLocal.get());
47 | }
48 |
49 | /*
50 | * (non-Javadoc)
51 | * @see javax.validation.MessageInterpolator#interpolate(java.lang.String,
52 | * javax.validation.MessageInterpolator.Context, java.util.Locale)
53 | */
54 | @Override
55 | public String interpolate(String message, Context context, Locale locale) {
56 | return defaultInterpolator.interpolate(message, context, locale);
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/LocaleThreadLocal.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.Locale;
22 |
23 | /**
24 | * {@link ThreadLocal} to store the Locale to be used in the message interpolator.
25 | */
26 | public class LocaleThreadLocal {
27 |
28 | public static final ThreadLocal THREAD_LOCAL = new ThreadLocal();
29 |
30 | public static Locale get() {
31 | return (THREAD_LOCAL.get() == null) ? Locale.getDefault() : THREAD_LOCAL.get();
32 | }
33 |
34 | public static void set(Locale locale) {
35 | THREAD_LOCAL.set(locale);
36 | }
37 |
38 | public static void unset() {
39 | THREAD_LOCAL.remove();
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/Person.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import javax.validation.constraints.NotNull;
22 | import javax.validation.constraints.Size;
23 | import javax.xml.bind.annotation.XmlAccessType;
24 | import javax.xml.bind.annotation.XmlAccessorType;
25 | import javax.xml.bind.annotation.XmlRootElement;
26 |
27 | @XmlRootElement
28 | @XmlAccessorType(XmlAccessType.FIELD)
29 | public class Person {
30 |
31 | @NotNull
32 | private Integer id;
33 |
34 | @NotNull
35 | @Size(min = 2, max = 50)
36 | private String name;
37 |
38 | public Integer getId() { return id; }
39 | public void setId(Integer id) { this.id = id; }
40 | public String getName() { return name; }
41 | public void setName(String name) { this.name = name; }
42 |
43 | @Override
44 | public int hashCode() {
45 | final int prime = 31;
46 | int result = 1;
47 | result = prime * result + ((id == null) ? 0 : id.hashCode());
48 | result = prime * result + ((name == null) ? 0 : name.hashCode());
49 | return result;
50 | }
51 |
52 | @Override
53 | public boolean equals(Object obj) {
54 | if (this == obj) {
55 | return true;
56 | }
57 | if (obj == null) {
58 | return false;
59 | }
60 | if (getClass() != obj.getClass()) {
61 | return false;
62 | }
63 | Person other = (Person) obj;
64 | if (id == null) {
65 | if (other.id != null) {
66 | return false;
67 | }
68 | } else if (!id.equals(other.id)) {
69 | return false;
70 | }
71 | if (name == null) {
72 | if (other.name != null) {
73 | return false;
74 | }
75 | } else if (!name.equals(other.name)) {
76 | return false;
77 | }
78 | return true;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/Persons.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.Collection;
22 | import java.util.concurrent.ConcurrentHashMap;
23 | import java.util.concurrent.ConcurrentMap;
24 |
25 | import javax.validation.constraints.NotNull;
26 | import javax.validation.constraints.Pattern;
27 | import javax.validation.constraints.Size;
28 | import javax.ws.rs.Consumes;
29 | import javax.ws.rs.FormParam;
30 | import javax.ws.rs.GET;
31 | import javax.ws.rs.POST;
32 | import javax.ws.rs.Path;
33 | import javax.ws.rs.PathParam;
34 | import javax.ws.rs.Produces;
35 | import javax.ws.rs.core.MediaType;
36 | import javax.ws.rs.core.Response;
37 |
38 | @Path("persons")
39 | @Produces(MediaType.APPLICATION_JSON)
40 | public class Persons {
41 |
42 | private static final ConcurrentMap persons = new ConcurrentHashMap();
43 |
44 | @GET
45 | public Collection getAll() {
46 | return persons.values();
47 | }
48 |
49 | @GET
50 | @Path("{id}")
51 | public Person getPerson(
52 | @PathParam("id")
53 | @NotNull(message = "The id must not be null")
54 | @Pattern(regexp = "[0-9]+", message = "The id must be a valid number")
55 | String id) {
56 | return persons.get(id);
57 | }
58 |
59 | @POST
60 | @Path("create")
61 | @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
62 | public Response createPerson(
63 | @FormParam("id")
64 | @NotNull(message = "{person.id.notnull}")
65 | @Pattern(regexp = "[0-9]+", message = "{person.id.pattern}")
66 | String id,
67 | @FormParam("name")
68 | @Size(min = 2, max = 50, message = "{person.name.size}")
69 | String name) {
70 | Person person = new Person();
71 | person.setId(Integer.valueOf(id));
72 | person.setName(name);
73 | persons.put(id, person);
74 | return Response.status(Response.Status.CREATED).entity(person).build();
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/ValidationConfigurationContextResolver.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.lang.reflect.Constructor;
22 | import java.lang.reflect.Method;
23 | import java.util.Arrays;
24 | import java.util.List;
25 |
26 | import javax.validation.BootstrapConfiguration;
27 | import javax.validation.Configuration;
28 | import javax.validation.ParameterNameProvider;
29 | import javax.validation.Validation;
30 | import javax.ws.rs.ext.ContextResolver;
31 | import javax.ws.rs.ext.Provider;
32 |
33 | import org.jboss.resteasy.plugins.validation.GeneralValidatorImpl;
34 | import org.jboss.resteasy.spi.validation.GeneralValidator;
35 |
36 | /**
37 | * Custom configuration of validation. This configuration can define custom:
38 | *
39 | *
MessageInterpolator - interpolates a given constraint violation message.
40 | *
TraversableResolver - determines if a property can be accessed by the Bean Validation provider.
41 | *
ConstraintValidatorFactory - instantiates a ConstraintValidator instance based off its class.
42 | *
ParameterNameProvider - provides names for method and constructor parameters.
*
43 | *
44 | */
45 | @Provider
46 | public class ValidationConfigurationContextResolver implements ContextResolver {
47 |
48 | /**
49 | * Get a context of type {@code GeneralValidator} that is applicable to the supplied type.
50 | *
51 | * @param type the class of object for which a context is desired
52 | * @return a context for the supplied type or {@code null} if a context for the supplied type is not available from
53 | * this provider.
54 | */
55 | @Override
56 | public GeneralValidator getContext(Class> type) {
57 | Configuration> config = Validation.byDefaultProvider().configure();
58 | BootstrapConfiguration bootstrapConfiguration = config.getBootstrapConfiguration();
59 |
60 | config.messageInterpolator(new LocaleSpecificMessageInterpolator(Validation.byDefaultProvider().configure()
61 | .getDefaultMessageInterpolator()));
62 | config.parameterNameProvider(new CustomParameterNameProvider());
63 |
64 | return new GeneralValidatorImpl(config.buildValidatorFactory(),
65 | bootstrapConfiguration.isExecutableValidationEnabled(),
66 | bootstrapConfiguration.getDefaultValidatedExecutableTypes());
67 | }
68 |
69 | /**
70 | * If method input parameters are invalid, this class returns actual parameter names instead of the default ones (
71 | * {@code arg0, arg1, ...})
72 | */
73 | private class CustomParameterNameProvider implements ParameterNameProvider {
74 |
75 | private final ParameterNameProvider nameProvider;
76 |
77 | public CustomParameterNameProvider() {
78 | nameProvider = Validation.byDefaultProvider().configure().getDefaultParameterNameProvider();
79 | }
80 |
81 | @Override
82 | public List getParameterNames(final Constructor> constructor) {
83 | return nameProvider.getParameterNames(constructor);
84 | }
85 |
86 | @Override
87 | public List getParameterNames(final Method method) {
88 | if ("getPerson".equals(method.getName())) {
89 | return Arrays.asList("id");
90 | }
91 | if ("createPerson".equals(method.getName())) {
92 | return Arrays.asList("id", "name");
93 | }
94 | return nameProvider.getParameterNames(method);
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/wildfly/src/main/java/com/samaxes/javax/rs/validation/ValidationExceptionMapper.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Integrating Bean Validation with JAX-RS in Java EE 7
3 | * https://github.com/samaxes/jaxrs-beanvalidation-javaee7
4 | *
5 | * Copyright (c) 2013 samaxes.com
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 | package com.samaxes.javax.rs.validation;
20 |
21 | import java.util.Iterator;
22 | import java.util.List;
23 |
24 | import javax.validation.ConstraintDeclarationException;
25 | import javax.validation.ConstraintDefinitionException;
26 | import javax.validation.GroupDefinitionException;
27 | import javax.validation.ValidationException;
28 | import javax.ws.rs.core.MediaType;
29 | import javax.ws.rs.core.Response;
30 | import javax.ws.rs.core.Response.ResponseBuilder;
31 | import javax.ws.rs.core.Response.Status;
32 | import javax.ws.rs.ext.ExceptionMapper;
33 | import javax.ws.rs.ext.Provider;
34 |
35 | import org.jboss.resteasy.api.validation.ResteasyViolationException;
36 | import org.jboss.resteasy.api.validation.Validation;
37 | import org.jboss.resteasy.api.validation.ViolationReport;
38 |
39 | /**
40 | * {@link ExceptionMapper} for {@link ValidationException}.
41 | *
42 | * Send a {@link ViolationReport} in {@link Response} in addition to HTTP 400/500 status code. Supported media types
43 | * are: {@code application/json} / {@code application/xml} (if appropriate provider is registered on server).
44 | *
45 | *
46 | * @see org.jboss.resteasy.api.validation.ResteasyViolationExceptionMapper The original WildFly class:
47 | * {@code org.jboss.resteasy.api.validation.ResteasyViolationExceptionMapper}
48 | */
49 | @Provider
50 | public class ValidationExceptionMapper implements ExceptionMapper {
51 |
52 | @Override
53 | public Response toResponse(ValidationException exception) {
54 | if (exception instanceof ConstraintDefinitionException) {
55 | return buildResponse(unwrapException(exception), MediaType.TEXT_PLAIN, Status.INTERNAL_SERVER_ERROR);
56 | }
57 | if (exception instanceof ConstraintDeclarationException) {
58 | return buildResponse(unwrapException(exception), MediaType.TEXT_PLAIN, Status.INTERNAL_SERVER_ERROR);
59 | }
60 | if (exception instanceof GroupDefinitionException) {
61 | return buildResponse(unwrapException(exception), MediaType.TEXT_PLAIN, Status.INTERNAL_SERVER_ERROR);
62 | }
63 | if (exception instanceof ResteasyViolationException) {
64 | ResteasyViolationException resteasyViolationException = ResteasyViolationException.class.cast(exception);
65 | Exception e = resteasyViolationException.getException();
66 | if (e != null) {
67 | return buildResponse(unwrapException(e), MediaType.TEXT_PLAIN, Status.INTERNAL_SERVER_ERROR);
68 | } else if (resteasyViolationException.getReturnValueViolations().size() == 0) {
69 | return buildViolationReportResponse(resteasyViolationException, Status.BAD_REQUEST);
70 | } else {
71 | return buildViolationReportResponse(resteasyViolationException, Status.INTERNAL_SERVER_ERROR);
72 | }
73 | }
74 | return buildResponse(unwrapException(exception), MediaType.TEXT_PLAIN, Status.INTERNAL_SERVER_ERROR);
75 | }
76 |
77 | protected Response buildResponse(Object entity, String mediaType, Status status) {
78 | ResponseBuilder builder = Response.status(status).entity(entity);
79 | builder.type(MediaType.TEXT_PLAIN);
80 | builder.header(Validation.VALIDATION_HEADER, "true");
81 | return builder.build();
82 | }
83 |
84 | protected Response buildViolationReportResponse(ResteasyViolationException exception, Status status) {
85 | ResponseBuilder builder = Response.status(status);
86 | builder.header(Validation.VALIDATION_HEADER, "true");
87 |
88 | // Check standard media types.
89 | MediaType mediaType = getAcceptMediaType(exception.getAccept());
90 | if (mediaType != null) {
91 | builder.type(mediaType);
92 | builder.entity(new ViolationReport(exception));
93 | return builder.build();
94 | }
95 |
96 | // Default media type.
97 | builder.type(MediaType.TEXT_PLAIN);
98 | builder.entity(exception.toString());
99 | return builder.build();
100 | }
101 |
102 | protected String unwrapException(Throwable t) {
103 | StringBuffer sb = new StringBuffer();
104 | doUnwrapException(sb, t);
105 | return sb.toString();
106 | }
107 |
108 | private void doUnwrapException(StringBuffer sb, Throwable t) {
109 | if (t == null) {
110 | return;
111 | }
112 | sb.append(t.toString());
113 | if (t.getCause() != null && t != t.getCause()) {
114 | sb.append('[');
115 | doUnwrapException(sb, t.getCause());
116 | sb.append(']');
117 | }
118 | }
119 |
120 | private MediaType getAcceptMediaType(List accept) {
121 | Iterator it = accept.iterator();
122 | while (it.hasNext()) {
123 | MediaType mt = it.next();
124 | /*
125 | * application/xml media type causes an exception:
126 | * org.jboss.resteasy.core.NoMessageBodyWriterFoundFailure: Could not find MessageBodyWriter for response
127 | * object of type: org.jboss.resteasy.api.validation.ViolationReport of media type: application/xml
128 | */
129 | /*if (MediaType.APPLICATION_XML_TYPE.getType().equals(mt.getType())
130 | && MediaType.APPLICATION_XML_TYPE.getSubtype().equals(mt.getSubtype())) {
131 | return MediaType.APPLICATION_XML_TYPE;
132 | }*/
133 | if (MediaType.APPLICATION_JSON_TYPE.getType().equals(mt.getType())
134 | && MediaType.APPLICATION_JSON_TYPE.getSubtype().equals(mt.getSubtype())) {
135 | return MediaType.APPLICATION_JSON_TYPE;
136 | }
137 | }
138 | return null;
139 | }
140 | }
141 |
--------------------------------------------------------------------------------
/wildfly/src/main/resources/ValidationMessages.properties:
--------------------------------------------------------------------------------
1 | person.id.notnull=The person id must not be null
2 | person.id.pattern=The person id must be a valid number
3 | person.name.size=The person name must be between {min} and {max} chars long
4 |
--------------------------------------------------------------------------------
/wildfly/src/main/resources/ValidationMessages_pt.properties:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/samaxes/jaxrs-beanvalidation-javaee7/e801ce84f3686e9c5e03b1a8285e2ce5abbff56f/wildfly/src/main/resources/ValidationMessages_pt.properties
--------------------------------------------------------------------------------
/wildfly/src/main/webapp/WEB-INF/beans.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
--------------------------------------------------------------------------------
/wildfly/src/main/webapp/index.jsp:
--------------------------------------------------------------------------------
1 | <%@page contentType="text/html" pageEncoding="UTF-8" %>
2 |
3 |
4 |
5 |
6 | Validating JAX-RS resource data with Bean Validation in Java EE 7
7 |
8 |
15 |
16 |
17 |
18 |
Validating JAX-RS resource data with Bean Validation in Java EE 7