Skip to content

Commit

Permalink
Use ZoneId instead of String for timezone related configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
geoand committed Mar 3, 2021
1 parent d983423 commit 8b9a7d2
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@ public Holder(Class<F> from, Class<T> to, Class<ObjectSubstitution<F, T>> substi

public final Holder<?, ?> holder;

public <F, T> ObjectSubstitutionBuildItem(Class<F> from, Class<T> to, Class<ObjectSubstitution<F, T>> substitution) {
holder = new Holder<>(from, to, substitution);
public <F, T> ObjectSubstitutionBuildItem(Class<F> from, Class<T> to,
Class<? extends ObjectSubstitution<F, T>> substitution) {
holder = new Holder(from, to, substitution);
}

public ObjectSubstitutionBuildItem(Holder<?, ?> holder) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.quarkus.deployment.recording.substitutions;

import java.time.ZoneId;

import io.quarkus.deployment.annotations.BuildProducer;
import io.quarkus.deployment.annotations.BuildStep;
import io.quarkus.deployment.builditem.ObjectSubstitutionBuildItem;

public class AdditionalSubstitutionsBuildStep {

@BuildStep
public void additionalSubstitutions(BuildProducer<ObjectSubstitutionBuildItem> producer) {
zoneIdSubstitutions(producer);
}

@SuppressWarnings("unchecked")
private void zoneIdSubstitutions(BuildProducer<ObjectSubstitutionBuildItem> producer) {
try {
/*
* We can't refer to these classes as they are package private but we need a handle on need
* because the bytecode recorder needs to have the actual class registered and not a super class
*/

Class<ZoneId> zoneRegionClass = (Class<ZoneId>) Class.forName("java.time.ZoneRegion");
producer.produce(new ObjectSubstitutionBuildItem(zoneRegionClass, String.class, ZoneIdSubstitution.class));

Class<ZoneId> zoneOffsetClass = (Class<ZoneId>) Class.forName("java.time.ZoneRegion");
producer.produce(new ObjectSubstitutionBuildItem(zoneOffsetClass, String.class, ZoneIdSubstitution.class));
} catch (ClassNotFoundException e) {
throw new IllegalStateException("Improper registration of ZoneId substitution", e);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package io.quarkus.deployment.recording.substitutions;

import java.time.ZoneId;

import io.quarkus.runtime.ObjectSubstitution;

public class ZoneIdSubstitution implements ObjectSubstitution<ZoneId, String> {

@Override
public String serialize(ZoneId obj) {
return obj.getId();
}

@Override
public ZoneId deserialize(String str) {
return ZoneId.of(str);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package io.quarkus.runtime.configuration;

import static io.quarkus.runtime.configuration.ConverterSupport.DEFAULT_QUARKUS_CONVERTER_PRIORITY;

import java.io.Serializable;
import java.time.ZoneId;

import javax.annotation.Priority;

import org.eclipse.microprofile.config.spi.Converter;

/**
* A converter to support locales.
*/
@Priority(DEFAULT_QUARKUS_CONVERTER_PRIORITY)
public class ZoneIdConverter implements Converter<ZoneId>, Serializable {

private static final long serialVersionUID = -439010527617997936L;

@Override
public ZoneId convert(final String value) {
return ZoneId.of(value);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TimeZone;

import javax.inject.Inject;
import javax.inject.Singleton;
Expand Down Expand Up @@ -179,23 +178,6 @@ private void registerModuleIfOnClassPath(String moduleClassName,
@Record(ExecutionTime.STATIC_INIT)
SyntheticBeanBuildItem pushConfigurationBean(JacksonRecorder jacksonRecorder,
JacksonBuildTimeConfig jacksonBuildTimeConfig) {

if (jacksonBuildTimeConfig.timezone.isPresent()) {
/*
* We need to make timezone a String instead of a java.util.TimeZone class
* because:
* 1) TimeZone cannot automatically be handled by the BytecodeRecorder
* 2) Handling it would require us to add non-JDK classes (i.e. sun.util.calendar.ZoneInfo) to bytecode recording
*/
String timeZoneStr = jacksonBuildTimeConfig.timezone.get();
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
if ("GMT".equals(timeZone.getID()) && !timeZoneStr.startsWith("GMT")) {
// Parsing an illegal TZ string value results in falling back to GMT...
throw new IllegalArgumentException(
"Value '" + timeZoneStr + "' is an invalid value for the 'quarkus.jackson.timezone' property");
}
}

return SyntheticBeanBuildItem.configure(JacksonConfigSupport.class)
.scope(Singleton.class)
.supplier(jacksonRecorder.jacksonConfigSupport(jacksonBuildTimeConfig))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.jackson.runtime;

import java.time.ZoneId;
import java.util.Optional;

import io.quarkus.runtime.annotations.ConfigItem;
Expand Down Expand Up @@ -28,5 +29,5 @@ public class JacksonBuildTimeConfig {
* If not set, Jackson will use its own default.
*/
@ConfigItem
public Optional<String> timezone;
public Optional<ZoneId> timezone;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package io.quarkus.jackson.runtime;

import java.time.ZoneId;

public class JacksonConfigSupport {

private final boolean failOnUnknownProperties;

private final boolean writeDatesAsTimestamps;

private final String timeZone;
private final ZoneId timeZone;

public JacksonConfigSupport(boolean failOnUnknownProperties, boolean writeDatesAsTimestamps, String timeZone) {
public JacksonConfigSupport(boolean failOnUnknownProperties, boolean writeDatesAsTimestamps, ZoneId timeZone) {
this.failOnUnknownProperties = failOnUnknownProperties;
this.writeDatesAsTimestamps = writeDatesAsTimestamps;
this.timeZone = timeZone;
Expand All @@ -22,7 +24,7 @@ public boolean isWriteDatesAsTimestamps() {
return writeDatesAsTimestamps;
}

public String getTimeZone() {
public ZoneId getTimeZone() {
return timeZone;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.quarkus.jackson.runtime;

import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand Down Expand Up @@ -34,10 +35,9 @@ public ObjectMapper objectMapper(Instance<ObjectMapperCustomizer> customizers,
// this feature is enabled by default, so we disable it
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
}
String timeZoneStr = jacksonConfigSupport.getTimeZone();
if (timeZoneStr != null) {
TimeZone timeZone = TimeZone.getTimeZone(timeZoneStr);
objectMapper.setTimeZone(timeZone);
ZoneId zoneId = jacksonConfigSupport.getTimeZone();
if (zoneId != null) {
objectMapper.setTimeZone(TimeZone.getTimeZone(zoneId));
}
List<ObjectMapperCustomizer> sortedCustomizers = sortCustomizersInDescendingPriorityOrder(customizers);
for (ObjectMapperCustomizer customizer : sortedCustomizers) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,11 @@
import static io.restassured.RestAssured.given;
import static org.hamcrest.CoreMatchers.is;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import io.quarkus.test.junit.QuarkusIntegrationTest;

@Disabled("This test seems flaky")
//@Disabled("This test seems flaky")
@QuarkusIntegrationTest
public class GreetingResourceIT {

Expand Down

0 comments on commit 8b9a7d2

Please sign in to comment.